TypicalMoronlmao
TypicalMoronlmao

Reputation: 53

Beginner Type Errors using Filter

I'm just starting to use Haskell, and I'm having what most of you reading would probably consider a beginner blunder.

Consider a list of tuples myTupleList = [(3,6),(4,8),(1,3)]

Nice. I wrote this function to return the list of tuples in which the second element in the first tuple, is double the first element: (Ex using myTupleList: double myTupleList , which returns [(3,6),(4,8)] )

double [] = []
double (x:xs)
   |(snd x) == 2 * (fst x) = x: double xs
   |otherwise              = double xs

Now I'm sure this isn't the prettiest function in the world, but it works. The problem now is adapting it to use filter. This is my current attempt:

double [] = []
double xs = filter ((2 * (fst(head xs))) == (snd(head xs))) xs

To my undestanding, filter recieves two arguments: a boolean expression and a list. However, I'm getting the following error:

Couldn't match expected type ‘(a, a) -> Bool’
              with actual type ‘Bool’
• Possible cause: ‘(==)’ is applied to too many arguments
  In the first argument of ‘filter’, namely
    ‘((2 * (fst (head xs))) == (snd (head xs)))’
  In the expression:
    filter ((2 * (fst (head xs))) == (snd (head xs))) xs
  In an equation for ‘double’:
      double xs = filter ((2 * (fst (head xs))) == (snd (head xs))) xs
• Relevant bindings include
    xs :: [(a, a)] (bound at Line 9, Column 8)
    double :: [(a, a)] -> [(a, a)] (bound at Line 8, Column 1)

I'm sure this is just some silly error or limitation of Haskell as a functional language that I'm not accustomed to or understanding properly, but it would be great to get some help with this.

Thanks

Upvotes: 5

Views: 85

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476699

filter expects a function a -> Bool, but (2 * (fst(head xs))) == (snd(head xs)) is not a function that maps an element to a Bool, but simply a Bool. It does not make much sense here to use head x, you use the parameter to get "access" to the element:

double :: (Eq a, Num a) => [(a, a)] -> [(a, a)]
double xs = filter (\x -> 2 * fst x == snd x) xs

You can use pattern matching to unpack the 2-tuple and thus no longer need fst and snd. Furthermore you can perform an η-reduction, and thus remove xs both in the head and the body of double in this case:

double :: (Eq a, Num a) => [(a, a)] -> [(a, a)]
double = filter (\(a, b) -> 2 * a == b)

This gives us:

Prelude> double [(3,6),(4,8),(1,3)]
[(3,6),(4,8)]

We can even make the predicate point-free:

double :: (Eq a, Num a) => [(a, a)] -> [(a, a)]
double = filter (uncurry ((==) . (2 *)))

Upvotes: 5

Related Questions