Alternative
is a bit of a hacky beast. It's essentially the class of monoid constructors: type constructors T
such that for any contained type X
, T X
is a monoid. This doesn't really have a lot to do with functors...monads, and is considerably less mathematically deep. (So, only for mathematical elegance, it would be a bit bad to set Monad
underneath Alternative
.)
Let's write that instance in terms of Monoid
for clarity (this won't actually compile):
instance (Foldable f, (∀ x . Monoid (f x))) => Monad f where
(>>=) = flip $ \f -> foldr mappend empty . fmap f
≡ flip $ \f -> fold . fmap f
≡ flip foldMap
or indeed
(=<<) = foldMap
so, this is definitely not something unknown.
To check the laws, we best look at the Kleisli formulation:
(f <=< g) x = f =<< g x
≡ foldMap f $ g x
i.e.
f <=< g = foldMap f . g
Then the monad laws are
Left identity
f <=< pure ≡ foldMap f . pure =! f
Right identity
pure <=< f ≡ foldMap pure . f =! f
Associativity
(f <=< g) <=< h ≡ foldMap (foldMap f . g) . h
=! foldMap f . foldMap g . h
≡ foldMap f . (foldMap g . h) ≡ f <=< (g <=< h)
So in brief, we need
foldMap f . pure =! f =! foldMap pure . f
∀ f
foldMap (foldMap f . g) =! foldMap f . foldMap g
∀ f
,g
That certainly looks not unreasonable, but I don't see whence you could rigorously conclude it for arbitrary Foldable
+Alternative
instances.
Really, the big problem I see with this instance is that it's not nearly general enough. Most monads are neither Foldable
nor Alternative
. If there was a cover-all definition like the one you propose, it would require OverlappingInstances
to define any instance of your own, and those are generally considered something you shouldn't use without good reason.
I do wonder however if there would be any problems with the following default definition for the bind method:
{-# LANGUAGE DefaultSignatures #-}
class Applicative f => Monad f where
return :: a -> m a
return = pure
(>>=) :: m a -> (a -> m b) -> m b
default (>>=) :: (Foldable m, Monoid m b)
=> m a -> (a -> m b) -> m b
(>>=) = flip foldMap
That would at least allow defining e.g. the list instance simply as
instance Monad []
without needing to write out the methods at all since sure enough, foldMap ≡ concatMap ≡ (=<<)
.