Search code examples
haskellfilterfold

Haskell implement a filter list with fold function


filterList :: (Eq a) => a -> [(a, b)] -> [(a, b)] 

>filterList " foo " [( " foo " , 1) , ( " bar " ,2) , ( " foo " ,3)]
[( " foo " ,1) ,( " foo " ,3)]

I have figured out two ways to solve this problem ,

`first way with list comprehension :` filterList a ((x,y):xs) =[(b,c)|(b,c)<-((x,y):xs),a==b]



  second way with recursive function: 
 filterList2 a []=[]
 filterList2 a ((x,y):xs)|a==x = (x,y):filterList2 a xs
                         |otherwise = filterList2 a xs

but I want to solve it with the folder function, and I am stuck.

filterList a ((x,y):xs) = foldr filter1 a ((x,y):xs)
                          
filter1 b ((x,y):xs)|b==x = (x,y)
                    |otherwise = filter1 b xs

which is not working.

A little help is really appreciated.


Solution

  • There are both problems with the filterList and filter1 function. The filterList function has as pattern:

    filterList a ((x, y): xs) = …

    but that does not make much sense, the type signature, and type inference will guarantee that it is a list of 2-tuples. Your pattern here will not work for an empty list, but filtering an empty list is likely still necessary. You thus should simplify it to:

    filterList a ls = …

    the foldr :: (a -> b -> b) -> b -> [a] -> b function is given three parameters:

    • the fold function
    • the "base-case", which is used when folding an empty list; and
    • a list of elements.

    But you can not use a as base case, since that base case also determines the type of the result. The base case is here the empty list. We also need to pass a to the filter1 function, so we can implement this as:

    filterList :: Eq a => a -> [(a, b)] -> [(a, b)]
    filterList a ls = foldr (filter1 a) [] ls

    Your filter1 function works on a list, but that is not how a foldr function works. The function you pass to foldr will be given an element, and the result of folding the rest of the list. Your function thus looks like:

    filter1 :: Eq a => a -> (a, b) -> [(a, b)] -> [(a, b)]
    filter1 a (x, y) rs = …

    Here a is the element we have passed we have to look for, (x, y) is the 2-tuple we are "folding in", and rs is the result of folding the rest of the list. So this is a list that is already filtered.

    I leave implementing filter1 as an exercise.