Search code examples
haskellfold

Making filter using foldr


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?


Solution

  • 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.