A better type signature for `forM_`

David Thomas davidleothomas at gmail.com
Fri Apr 1 17:03:27 UTC 2016


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
>


More information about the Libraries mailing list