Reputation: 53
I have a list [Maybe a] where I want to cut out the Nothing elements with a function that uses foldl For example cut [Just 2, Just 10, Nothing, Just 5] -> [2,10,5]
I wrote:
cut :: [Maybe a] -> [a]
cut a = foldl (help) [] a
where help (x:xs) Nothing = (x:xs)
help (x:xs) Just a = a:(x:xs)
Where is my mistake?
Upvotes: 2
Views: 221
Reputation: 476719
By writing help (x:xs) Nothing = (x:xs)
you have used a pattern (x:xs)
this means that you expect the accumulator to be a list with at least one element. But that is not always the case, for instance the initial accumulator []
is the empty list.
We can simply use a variable l
, instead of a pattern:
cut :: [Maybe a] -> [a]
cut a = foldl help [] a
where help l Nothing = l
help l (Just a) = a:l
Note that you also need to add brackets for a constructor with arguments.
But this will not solve the entire pattern, now you will have reversed the list. This is because foldl
iterates through the list left-to-right, so you prepend values while you iterate through the list. We can use foldr
instead. But now the type of the function does no longer works, since the help
function in foldr
takes the accumulator as second argument. So we can flip the arguments:
cut :: [Maybe a] -> [a]
cut a = foldr help [] a
where help Nothing l = l
help (Just a) l = a:l
And now it works. We can however clean up the code a bit. For instance use an eta-reduction on the cut
function: we can remove a
in the head and body of the function:
cut :: [Maybe a] -> [a]
cut = foldr help []
where help Nothing l = l
help (Just a) l = a:l
and since the second argument in help
can be removed and the body converted into functions:
cut :: [Maybe a] -> [a]
cut = foldr help []
where help Nothing = id
help (Just a) = (a:)
We can also use another catamorphism: foldr
is the catamorphism of a list, and maybe
is the catamorphism of Maybe
, so we can write a:
maybe <value-in-case-of-nothing> <function-just-value> <Maybe value>
So we can rewrite our help
to:
import Data.Maybe(maybe)
cut :: [Maybe a] -> [a]
cut = foldr help []
where help = maybe id (:)
or simply inject it as an argument of foldr
:
import Data.Maybe(maybe)
cut :: [Maybe a] -> [a]
cut = foldr (maybe id (:)) []
So now we used a catamporhism inside a catamorphism, so catamorphception.
Upvotes: 3