A better type signature for `forM_`

David Feuer david.feuer at gmail.com
Fri Apr 1 17:08:37 UTC 2016


No, we can't in general. With the exception of Control.Arrow (why that
exception? No clue!) GHC's rewrite rules try very hard not to change the
meaning of even bad user code. Yes, x <$ xs is supposed to be equivalent to
fmap (const x) xs, and fmap is supposed to obey the functor laws. But
neither of these is guaranteed, so a rewrite rule depending on these laws
could change the meaning of user code.
On Apr 1, 2016 1:03 PM, "David Thomas" <davidleothomas at gmail.com> wrote:

> If we provide (under whatever names) both the discard-value and the
> require-unit versions, then at least for the inlined case we could
> safely remove the overhead of void with a rewrite rule.
>
> On Fri, Apr 1, 2016 at 8:12 AM, Bryan Richter <b at chreekat.net> wrote:
> > On Fri, Apr 01, 2016 at 10:23:24AM -0400, davean wrote:
> >> On Fri, Apr 1, 2016 at 1:13 AM, Erik de Castro Lopo wrote:
> >>
> >> > Which is the exact problem. I suspect that most people use `forM_`
> >> > as "assume the action returns unit" rather than "assume the return
> >> > value of the action is ignored".
> >> >
> >>
> >> A review of my code shows I mostly use it as "assume the return value of
> >> the action is ignored".
> >>
> >> Many things return data that is sometimes useful, but not always.
> Rarely do
> >> they have an '_' variant or the like to allow you to be more specific.
> >
> > (emphasis added:)
> >
> >> I wouldn't find it to be overly onerous to throw "void" in in those
> >> cases though.
> >
> > The first email in this thread hinted at another possible solution,
> > with "unexpected behavior from... code that... has zero warning (even
> > with -Wall)."
> >
> > Even if forM_ gets a new type, I don't think people will be much
> > assisted with the new message:
> >
> >     Expected: IO ()
> >     Actual: IO (IO Int)
> >
> > That message actually mixes two different problems. If the wisdom
> > becomes "throw a void on it", which I've already seen suggested a few
> > times, you easily get back to the original problem. Change the body of
> > the lambda to
> >
> >     void $ maybe (HT.insert ht k v) (const $ abort k) <$> HT.lookup ht k
> >     ^^^^^^^
> >
> > ...and now it *still* typechecks without warnings, but the original
> > problem remains.
> >
> > Better, if possible, would be
> >
> >     Warning: Discarded monadic value [in forM_]
> >
> > Even that wouldn't catch my 'void $' above, but it also wouldn't
> > be indirectly *suggesting* it as a solution.
> >
> > However, the thing Snoyberg raised about performance seems important.
> > Busting the stack while trying to throw away variables seems
> > unfortunate. Is Free the best counterexample to the "performance" of
> > `t a -> (a -> m ()) -> m ()`? Does Free really matter? It's not
> > exactly known for being a performant option.
> >
> > _______________________________________________
> > Libraries mailing list
> > Libraries at haskell.org
> > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
> >
> _______________________________________________
> Libraries mailing list
> Libraries at haskell.org
> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/libraries/attachments/20160401/1ce7be1f/attachment.html>


More information about the Libraries mailing list