<div dir="ltr">+1.<br><br>I also remember this post by Neil Mitchell which seems appropriate: <a href="http://neilmitchell.blogspot.com/2008/12/mapm-mapm-and-monadic-statements.html">http://neilmitchell.blogspot.com/2008/12/mapm-mapm-and-monadic-statements.html</a>. He also uses the name &quot;ignore&quot; for your function.<br>
<br>Michael<br><br><div class="gmail_quote">On Wed, Jun 10, 2009 at 7:53 PM, Gwern Branwen <span dir="ltr">&lt;<a href="mailto:gwern0@gmail.com">gwern0@gmail.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
-----BEGIN PGP SIGNED MESSAGE-----<br>
Hash: SHA512<br>
<br>
So while writing my wp-archivebot, I ran into the issue that forkIO<br>
requires IO () but returns IO ThreadId, and that many useful IO<br>
functions will return IO a instead of IO ().<br>
<br>
This forces some awkward contortions. Suppose I want to ping the<br>
WebCite website at a particular address, and this request makes<br>
WebCite archive a URL embedded in that address. Presumably I could<br>
venture into the depths of Network.HTTP to figure out how to ping an<br>
URL without also pulling down the server&#39;s HTML, but why do that when<br>
I already have obviously &#39;openURL :: String -&gt; IO String&#39;?  Much<br>
easier to do something like &#39;openURL &quot;<a href="http://webcite.org" target="_blank">webcite.org</a>&quot; ++ foo ++ &quot;other<br>
stuff&quot; &#39;.<br>
<br>
But my bot needs to handle quite a few URLs; one at a time, what with<br>
all the waits and timeouts, isn&#39;t going to hack it. So for a given<br>
link, I forkIO the openURL request. But of course, forkIO demands IO<br>
(), so I toss in a &#39;&gt;&gt; return ()&#39;. Fair enough.<br>
<br>
So I examine the performance, and it&#39;s still too slow. Recent Changes<br>
has hundreds of different pages a minute. I&#39;d better fork each page<br>
(and then fork for each link). But wait, all those forkIOs are<br>
returning IO ThreadIds, and my top-level forkIO call demands IO ()...<br>
So another &gt;&gt; return (). At this point, the code is starting to look<br>
pretty silly - something like &#39;...stuff &gt;&gt; return ()) &gt;&gt; return ())&#39;.<br>
<br>
So I see the repeated pattern, and by the rule of 3, factor it out to:<br>
<br>
- -- | Convenience function. &#39;forkIO&#39; and &#39;forM_&#39; demand return types of<br>
&#39;IO ()&#39;, but most interesting<br>
- -- IO functions don&#39;t return void. So one adds a call to &#39;return ()&#39;;<br>
this just factors it out.<br>
ignore ∷ (Monad m) ⇒  m a →  m ()<br>
ignore x = x &gt;&gt; return ()<br>
<br>
Not the most complex convenience function I&#39;ve ever written, but not<br>
any simpler than, say Control.Monad.forever or for that matter, most<br>
of the stuff in Control.Monad.<br>
<br>
I&#39;d think it&#39;d be useful for more than just me. Agda is lousy with<br>
calls to &#39;&gt;&gt; return ()&#39;; and then there&#39;s ZMachine, arrayref, whim,<br>
the barracuda packages, binary, bnfc, buddha, bytestring, c2hs, cabal,<br>
chesslibrary, comas, conjure, curl, darcs, darcs-benchmark,<br>
dbus-haskell, ddc, dephd, derive, dhs, drift, easyvision, ehc,<br>
filestore, folkung, geni, geordi, gtk2hs, gnuplot, ginsu, halfs,<br>
happstack, haskeline, hback, hbeat... You get the picture.<br>
<br>
I realize the specific name of &#39;ignore&#39; can be bikeshedded to death,<br>
but it&#39;s clear, it&#39;s short, Hoogle turns up one other function with<br>
ignore in its name (Distribution.ParseUtils ignoreUnrec), and it&#39;s<br>
been independently named &#39;ignore&#39; by another Haskeller (lilac).<br>
<br>
Existing uses of the string &#39;ignore are rare - it&#39;s in a few places as<br>
a variable, cabal and cabal-install and ehc and tar have where<br>
definitions of an ignore, a test for directory defines an ignore and<br>
imports Control.Monad unqualified, fit defines an &#39;ignore&#39; but doesn&#39;t<br>
seem to use it in any module that also imports Control.Monad<br>
unqualified, halipeto defines an ignore but doesn&#39;t import<br>
Control.Monad, shim/yi has a let definition of an ignore, yhc has a<br>
where definition of an ignore. And that&#39;s about it. One of directory&#39;s<br>
tests would break, and the rest might have an additional -Wall<br>
warning.<br>
<br>
- --<br>
gwern<br>
-----BEGIN PGP SIGNATURE-----<br>
Version: GnuPG v1.4.9 (GNU/Linux)<br>
<br>
iEYEAREKAAYFAkov5Q0ACgkQvpDo5Pfl1oIsRQCghUqynThzcT+OYV1KaYJhGFhv<br>
6yYAnjf7CVOm0+Fg1FBa9IpdVIrRpCZm<br>
=Cd8V<br>
-----END PGP SIGNATURE-----<br>
_______________________________________________<br>
Libraries mailing list<br>
<a href="mailto:Libraries@haskell.org">Libraries@haskell.org</a><br>
<a href="http://www.haskell.org/mailman/listinfo/libraries" target="_blank">http://www.haskell.org/mailman/listinfo/libraries</a><br>
</blockquote></div><br></div>