Thanks Jonas,<div><br></div><div>I feel much better already:</div><div><br></div><blockquote class="webkit-indent-blockquote" style="margin: 0 0 0 40px; border: none; padding: 0px;"><div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">import Control.Concurrent</font></div>
</div><div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">import Control.Exception</font></div></div><div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">import Control.Monad</font></div>
</div><div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">import Network</font></div></div><div><div><span class="Apple-style-span" style="font-family: &#39;courier new&#39;, monospace; ">import System.IO</span></div>
</div><div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">import System.IO.Error (isEOFError)</font></div></div></blockquote><div><div><br></div></div><blockquote class="webkit-indent-blockquote" style="margin: 0 0 0 40px; border: none; padding: 0px;">
<div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">main = withSocketsDo $ do</font></div></div><div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">  sListen &lt;- listenOn (PortNumber 8000)</font></div>
</div><div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">  putStrLn &quot;Listening on Port 8000&quot;</font></div></div><div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">  forkIO $ forever $ do</font></div>
</div><div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">    (sSession, hostname, port) &lt;- accept sListen</font></div></div><div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">    putStrLn (&quot;Connected to &quot; ++ hostname ++ &quot;:&quot; ++ show port)</font></div>
</div><div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">    forkIO $ echoLines sSession</font></div></div><div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">  putStrLn &quot;Press &lt;CTRL-D&gt; to quit.&quot;</font></div>
</div><div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">  exitOn</font><span class="Apple-style-span" style="font-family: &#39;courier new&#39;, monospace; ">Eof</span></div></div><div><div>
<font class="Apple-style-span" face="&#39;courier new&#39;, monospace"><br></font></div></div><div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">echoLines h = try (hGetLine h) &gt;&gt;= either</font></div>
</div><div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">  (\e -&gt; if isEOFError e then print e else ioError e)</font></div></div><div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">  (putStrLn &gt;=&gt; const (echoLines h))</font></div>
</div><div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace"><br></font></div></div><div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">exitOnEof = try getLine &gt;&gt;= either</font></div>
</div><div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">  (\e -&gt; unless (isEOFError e) $ ioError e)</font></div></div><div><div><font class="Apple-style-span" face="&#39;courier new&#39;, monospace">  (const exitOnEof)</font></div>
</div></blockquote><div><div><br></div><div>I also worked out I didn&#39;t <font class="Apple-style-span" face="&#39;courier new&#39;, monospace">void </font>by making <font class="Apple-style-span" face="&#39;courier new&#39;, monospace">processLines </font>(now <font class="Apple-style-span" face="&#39;courier new&#39;, monospace">echoLines h</font>) be <font class="Apple-style-span" face="&#39;courier new&#39;, monospace">forkIO</font>&#39;s argument rather than <font class="Apple-style-span" face="&#39;courier new&#39;, monospace">forkIO</font>&#39;s result.</div>
<div><br></div><div>Cheers,</div><div><br></div><div>-John</div><br><div class="gmail_quote">2011/6/28 Jonas Almström Duregård <span dir="ltr">&lt;<a href="mailto:jonas.duregard@chalmers.se">jonas.duregard@chalmers.se</a>&gt;</span><br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">There is the <span style="font-family:courier new,monospace">void</span> function in Control.Monad:<br><a href="http://hackage.haskell.org/packages/archive/base/latest/doc/html/Control-Monad.html#v:void" target="_blank">http://hackage.haskell.org/packages/archive/base/latest/doc/html/Control-Monad.html#v:void</a><br>

<br>Instead of using <span style="font-family:courier new,monospace">return ()</span> you can just use <span style="font-family:courier new,monospace">void processLine</span>.<br><br>Also some people like to use the either function instead of matching on Left/Right. In this case you can also avoid introducing a few names:<br>

<br> <span style="font-family:courier new,monospace">   let processLine = void $ forkIO $</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">          try (hGetLine sSession) &gt;&gt;= either</span><br style="font-family:courier new,monospace">

<span style="font-family:courier new,monospace">            (\e -&gt; if isEOFError e <br>             then print e <br>             else ioError e)</span><br style="font-family:courier new,monospace"><span style="font-family:courier new,monospace">            (putStrLn &gt;=&gt; const processLine)</span><div>
<div></div><div class="h5"><br>
<br>On 28 June 2011 12:58, John Ky &lt;<a href="mailto:newhoggy@gmail.com" target="_blank">newhoggy@gmail.com</a>&gt; wrote:<br>&gt; Hi Eric, Ivan,<br>&gt; On 28 June 2011 18:32, Erik de Castro Lopo &lt;<a href="mailto:mle%2Bhs@mega-nerd.com" target="_blank">mle+hs@mega-nerd.com</a>&gt; wrote:<br>

&gt;&gt;<br>&gt;&gt; The hlint program would have flagged both of those and possibly<br>&gt;&gt; others. See:<br>&gt;<br>&gt; Cool!<br>&gt; It didn&#39;t flag either for me, but it recommended replacing ++ (show port)<br>

&gt; with ++ show port, if then else with unless, putStrLn (show x) with print x,<br>&gt; and do stuff with stuff.<br>&gt; All useful to know.<br>&gt; On 28 June 2011 18:16, Ivan Lazar<br>&gt; Miljenovic &lt;<a href="mailto:ivan.miljenovic@gmail.com" target="_blank">ivan.miljenovic@gmail.com</a>&gt; wrote:<br>

&gt;&gt;<br>&gt;&gt; I don&#39;t think you need all those return () everywhere...<br>&gt;<br>&gt;  <br>&gt; You&#39;re right.  At some point I added it in to (try to) make the compiler<br>&gt; happy, but it must have been or become unnecessary.<br>

&gt; I still need two though because forkIO (and therefore my processLine<br>&gt; function) returns IO ThreadId, but the last line for do notation must be<br>&gt; return () (see below).<br>&gt; On 28 June 2011 18:16, Ivan Lazar<br>

&gt; Miljenovic &lt;<a href="mailto:ivan.miljenovic@gmail.com" target="_blank">ivan.miljenovic@gmail.com</a>&gt; wrote:<br>&gt;&gt;<br>&gt;&gt; And at the end, why do you do &quot;line &lt;- getLine&quot; when you don&#39;t use the<br>
&gt;&gt; result?<br>
&gt;<br>&gt; Oh that.  I was trying to figure out a way to terminate by program.  I&#39;ve<br>&gt; now changed it to exit on EOF.<br>&gt; Here is my second attempt.  Is it much better?:<br>&gt;<br>&gt; import Control.Concurrent<br>

&gt; import Control.Exception<br>&gt; import Control.Monad<br>&gt; import Network<br>&gt; import System.IO<br>&gt; import System.IO.Error (isEOFError)<br>&gt; main = withSocketsDo $ do<br>&gt;   sListen &lt;- listenOn (PortNumber 8000)<br>

&gt;   putStrLn &quot;Listening on Port 8000&quot;<br>&gt;   forkIO $ forever $ do<br>&gt;     (sSession, hostname, port) &lt;- accept sListen<br>&gt;     putStrLn (&quot;Connected to &quot; ++ hostname ++ &quot;:&quot; ++ show port)<br>

&gt;     let processLine = forkIO $ do<br>&gt;         lineResult &lt;- try (hGetLine sSession)<br>&gt;         case lineResult of<br>&gt;           Right line -&gt; do<br>&gt;             putStrLn line<br>&gt;             processLine<br>

&gt;             return ()<br>&gt;           Left e -&gt; if isEOFError e<br>&gt;             then print e<br>&gt;             else ioError e<br>&gt;     processLine<br>&gt;     return()<br>&gt;   putStrLn &quot;Press &lt;CTRL-D&gt; to quit.&quot;<br>

&gt;   let processStdIn = do<br>&gt;       lineResult &lt;- try getLine<br>&gt;       case lineResult of<br>&gt;         Right line -&gt; processStdIn<br>&gt;         Left e -&gt; unless (isEOFError e) $ ioError e<br>&gt;   processStdIn<br>

&gt;<br>&gt; Thanks for the suggestions.<br>&gt; Cheers,<br>&gt; -John<br>&gt;<br></div></div><div><div></div><div class="h5">&gt; _______________________________________________<br>&gt; Haskell-Cafe mailing list<br>&gt; <a href="mailto:Haskell-Cafe@haskell.org" target="_blank">Haskell-Cafe@haskell.org</a><br>

&gt; <a href="http://www.haskell.org/mailman/listinfo/haskell-cafe" target="_blank">http://www.haskell.org/mailman/listinfo/haskell-cafe</a><br>&gt;<br>&gt;<br><br>
</div></div></blockquote></div><br></div>