I'm trying to make filter
using foldr
. I have a solution, but don't know why my version does not work.
foldr
works like this:
>>>foldr op z (xs:x)
x op z
then repeats, correct? When x is the last element in the list.
Now, I have
myFilter pred = foldr op z
where
z = []
op x xs = if pred x then x
this does not work, gives a parse error (possibly incorrect indentation or mismatched brackets)
error.
The operation just gives x
to pred
and if it is true
, returns x
, otherwise skips it. The way foldr
works is that it keeps looping on the xs
list that is passed. So why do I need to do
op x xs = if pred x then x : xs else xs
and tell it to continue with xs
even if foldr
already does the continuing?
Let's take a look at the type of foldr
for a list:
foldr :: (a -> b -> b) -> b -> [a] -> b
Now you are using it like this:
foldr op z
From the type signature of foldr
we see that the function op
must return something of type b
which is the same type as z
. Since you do z = []
, this must be a list. So the result of op x xs
must be a list.
Additionally, keep in mind that if...else
in Haskell is an expression. This means that it must evaluate to some value no matter if the condition is true or false. In other languages, the else
is optional because if
is a statement. In Haskell, the else
is not optional.
So why do I need to do
op x xs = if pred x then x : xs else xs
and tell it to continue with xs even if foldr already does the continuing?
One reason is that op
must always return a value. This value will be used by foldr
to continue its calculation. Without it, foldr
is unable to continue, and in fact your code won't even compile as you saw.