Strictness of Semigroup instance for Maybe

Ryan Reich ryan.reich at gmail.com
Wed May 23 01:19:19 UTC 2018


I second this expectation. I've recently had a hard time ensuring laziness
in my work and it's been comforting in rooting out failures to know that
the standard libraries, at least, are concerned about it.

On Tue, May 22, 2018, 16:57 Tikhon Jelvis <tikhon at jelv.is> wrote:

> I think the extra laziness makes sense here—it matches the behavior of
> common functions like &&. My general expectation is that functions are as
> lazy as they can be and, in the case of operators with two arguments, that
> evaluation goes left-to-right. (Again like &&.)
>
> On Tue, May 22, 2018 at 4:37 PM, David Feuer <david.feuer at gmail.com>
> wrote:
>
>> I think extra laziness here would be a bit surprising.
>>
>> On Tue, May 22, 2018 at 5:57 PM, Donnacha Oisín Kidney
>> <mail at doisinkidney.com> wrote:
>> > The current semigroup instance  for Maybe looks like  this:
>> >
>> >     instance Semigroup a => Semigroup (Maybe a) where
>> >         Nothing <> b       = b
>> >         a       <> Nothing = a
>> >         Just a  <> Just b  = Just (a <> b)
>> >
>> > However, it could be lazier:
>> >
>> >     instance Semigroup a => Semigroup (Maybe a) where
>> >         Nothing <> b = b
>> >         Just a  <> b = Just (maybe a (a<>) b)
>> >
>> > This causes different behaviour for Data.Semigroup.First and
>> > Data.Monoid.First:
>> >
>> >     >>>  Data.Monoid.getFirst . foldMap pure $ [1..]
>> >     Just 1
>> >     >>>  fmap Data.Semigroup.getFirst . Data.Semigroup.getOption .
>> foldMap
>> > (pure.pure) $ [1..]
>> >     _|_
>> >
>> > A different definition for `Option` gets back the old behaviour:
>> >
>> >     newtype LeftOption a = LeftOption { getLeftOption :: Maybe a }
>> >
>> >     instance Semigroup a => Semigroup (LeftOption a) where
>> >       LeftOption Nothing <> ys = ys
>> >       LeftOption (Just x) <> LeftOption ys = LeftOption (Just (maybe x
>> (x<>)
>> > ys))
>> >
>> >     instance Semigroup a => Monoid (LeftOption a) where
>> >       mempty = LeftOption Nothing
>> >       mappend = (<>)
>> >
>> >     >>> fmap Data.Semigroup.getFirst . getLeftOption . foldMap
>> (LeftOption .
>> > Just . Data.Semigroup.First) $ [1..]
>> >     Just 1
>> >
>> > Is there any benefit to the extra strictness? Should this be changed?
>> >
>> > Another consideration is that the definition could equivalently be
>> > right-strict, to get the desired behaviour for Last, but I think the
>> > left-strict definition probably follows the conventions more.
>> >
>> > I originally posted this to reddit
>> > (
>> https://www.reddit.com/r/haskell/comments/8lbzan/semigroup_maybe_too_strict/
>> )
>> > and was encouraged to post it here.
>> >
>> > _______________________________________________
>> > 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
>>
>
> _______________________________________________
> 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/20180522/db94c38f/attachment.html>


More information about the Libraries mailing list