[Haskell-beginners] Maybe, Either

Conor McBride conor at strictlypositive.org
Tue Sep 15 04:21:02 EDT 2009


Hi

This topic comes up a lot, and this is what I usually say when
it does. It's a thing I learned from James McKinna, many years
ago...

Might I gently suggest that there is a much better, more
natural way to abstract over every type-former which has
some sort of return/pure-like thing and some sort of mzero/empty
like thing? You could use the type-former which is inductively
defined to be the least such thing, and as such has a canonical
mapping to all the others, namely Maybe.

It's not necessarily a good idea to fix on Monad or MonadPlus
as there are other choices. For example,

On 15 Sep 2009, at 07:14, Yusaku Hashimoto wrote:

> I prefer Alternative to MonadPlus for explaining failure. It has
> better name and operator for failure and try-another.
>
> import Control.Applicative
>
> aLookup :: (Alternative f, Eq k) => k -> [(k,v)] -> f v
> aLookup key pairs = maybe empty pure $ lookup key pairs

there are notorious non-monadic instances for the above f
(some formulations of parsing, in particular). So,

>> I understand that fail being in Monad is controversial, but my  
>> version of
>> the function works in *all* monads.

this is a touch presumptuous. On the one hand, Brent is right
when he says

 > It doesn't work in *all* monads -- it only works in monads which
 > support a sensible notion of failure.

but he's perhaps excessive when he says

 > This is exactly what is captured by the MonadPlus constraint
 > on my version of mLookup.

because it's not exact: it requires mplus as well as a sensible
notion of failure. And yes, why should we insist on (>>=) when
we just need a return and an mzero?  Incidentally, I don't know
where the MonadPlus instance

 > (IO, Maybe, [], ...) are already instances of MonadPlus.

of IO is coming from, but I want it caught and locked up now (in
STM, for example) before it does any permanent damage.

Why not factor out the failure-prone operations from the business
of interpreting failure in some failure-supporting context? Work
concretely while you can (types stay shorter, error messages make
more sense) then apply adapters

malt :: Alternative f => Maybe x -> f x
malt = maybe empty pure

mop :: MonadPlus m => Maybe x -> m x
mop = maybe mzero return

when you need to? This also reduces the risk of connecting an
ambiguous supplier to an ambiguous consumer, (show . read) style.

The message clearly bears repeating. Inductive definition is
a concrete form of abstraction. Don't be fooled by its
appearance: Maybe is the most abstract choice here -- the
classier options demand more structure than is needed and
thus exclude use-cases.

I'll crawl back under my stone now.

All the best

Conor



More information about the Beginners mailing list