I'm learning list operations in Haskell and now I'm trying out various list operations on Maybe list type. Currently, I have this implementation of sum of elements in list in Haskell
sum :: Num a => [a] -> a
sum [] = 0
sum (a:t) = a + sum t
Now I want to do the same thing but instead of returning the value, I want to return a Maybe type instead. And when the list given is empty it should return Nothing.
I've come up with this
sum :: Num a => [a] -> Maybe a
sum [] = Nothing
sum (a:t) = fmap (a+) (sum t)
But the result of all non empty list given results in Nothing.
From what I understand, the list given will eventually pattern match with the empty list therefore returning Nothing.
How do I fix this so that it returns the expected value and of Maybe type. I can't figure out how to make it work recursively as the normal sum implementation above, so I guess there should be another way. Would prefer if only Prelude module is imported as I'm still trying to absorb stuff inside the Prelude module.
The problem is that your recursive function always uses the empty list as a base case, so your base case value is always Nothing
. You only want to return Nothing
if the "root" call takes an empty list. Otherwise, you want to use the singleton list as your base case.
sum :: Num a => [a] -> Maybe a
sum [] = Nothing
sum [x] = Just x
sum (a:t) = fmap (a+) (sum t)
This way, sum []
will never be reached by a recursive call; any non-empty list will hit the base case sum [x]
first.
Another way to organize this is to use your original total function as a helper that sums non-empty lists only, and handle the empty list separately.
sum :: Num a => [a] -> Maybe a
sum [] = Nothing
sum xs = sum' xs
where sum' [] = Just 0
sum' (a:t) = fmap (a+) (sum' t)
Note that sum'
can be called on an empty list, but only if it is originally called on a non-empty list.
As @chi points out, the helper function doesn't need to use Maybe
at all; since it only sums non-empty lists, you can skip using fmap
and sum the list normally; only the final result needs to be wrapped in Just
:
sum :: Num a => [a] -> Maybe a
sum [] = Nothing
sum xs = Just (sum' xs)
where sum' [] = 0
sum' (a:t) = a + sum' t