Why is Maybe's Semigroup instance biased towards Just and the Monoid uses Nothing as its empty element?

  • A+

Maybe expresses computations that might not produce a result due to an error. Therefore such computations must be short circuited.

Now Maybe's Semigroup/Monoid instances seem to break with this semantics, because the former is biased towards Just and the latter treats the error case Nothing as its empty element:

Just "foo" <> Nothing -- Just "foo" Nothing <> Just "bar" -- Just "bar" Just "foo" <> Just "bar" -- Just "foobar" Nothing <> Nothing -- Nothing 

I would expect Nothing for the first two cases.

Here is the alternative implementation (hopefully it is correct/lawful):

instance Semigroup a => Semigroup (Maybe a) where     Nothing <> _       = Nothing     _       <> Nothing = Nothing     Just a  <> Just b  = Just (a <> b)  instance Monoid a => Monoid (Maybe a) where   mempty = Just mempty 

I don't want to say that these alternative instances are better. But they seem useful too. So why was a selection made in the first place instead of leaving the implementation to the user?

Your instance is actually a special case of a much more general instance for applicative functors.

newtype LiftA f a = LiftA { getLiftA :: f a }  instance (Applicative f, Semigroup a) => Semigroup (LiftA f a) where     LiftA x <> LiftA y = LiftA $ liftA2 (<>) x y  instance (Applicative f, Monoid a) => Monoid (LiftA f a) where     mempty = LiftA $ pure mempty 

Which I assumed would be in the standard library somewhere (under a different name probably) but I couldn't find it. But the existence of this general instance could be one reason to choose the library version of Maybe, which is more of Maybe's special power. On the other hand, it's quite nice when your algebraic structures are all coherent with each other; i.e. when a type is an Applicative, use the "LiftA"-style instance whenever possible (on all F-algebra classes).

On the third hand (!), we can't have coherence everywhere, since the library instance agrees with Maybe's MonadPlus instance. This is strikingly parallel to the fact that there are two monoids on natural numbers: addition and multiplication. For numbers, we just picked not to have any monoid instance because it's unclear which to use.

In conclusion, I don't know. But maybe this information was helpful.

