Got stuck again while trying to learn some Haskell. What I'm trying to do is implementing a combined head/tail
method for lists with error handling. The signature must look like this:
head' :: MonadPlus m => [a] -> m (a,[a])
However I'm a bit lost at how error handling with MonadPlus works. I tried the following:
head' xs = if (length xs > 0) then Just(head xs, tail xs) else Nothing
but it complains: Expected type: m (a, [a]) Actual type: Maybe (a, [a]). Just for fun I also tried:
head' xs = if (length xs > 0) then Just(head xs, tail xs) else Nothing `mplus` Nothing
but not only does that look redundant, it also does not work either.
Any hints appreciated!
Try this:
head' :: MonadPlus m => [a] -> m (a,[a])
head' xs = if null xs then mzero then return (head xs, tail xs)
mzero
is the "nothing" or (indeed) "zero" value, which you can use here to model the absence of a result. It has type m x
for any type x
and monad with zero m
, so it fits here.
Instead, return
wraps any value in any monad. In particular, you can insert our (a,[a])
pair inside m
. (This does not even require the monad to be a MonadPlus
)
Note how in the code above we did not mention any specific monad: the code is indeed generic, so that it can work with any MonadPlus
.
Lastly, I used null
instead of length ... > 0
since null
only examines the first constructor in the list, while length ... > 0
has to traverse it all.
You can actually remove the check by switching to pattern matching:
head' :: MonadPlus m => [a] -> m (a,[a])
head' [] = mzero
head' (x:xs) = return (x, xs)