fabian789
fabian789

Reputation: 8412

Confusion about combining functions with $ and zip

The following function takes two lists returns all elements that occur in both lists at the same indices:

equal_els :: Eq a => [a] -> [a] -> [a]
equal_els xs ys = map fst $ filter (uncurry (==)) $ zip xs ys

Seeing how xs ys occurs at the end on both sides, I did what I always do in that case: remove it! However, the resulting

equal_els = map fst $ filter (uncurry (==)) $ zip

does not compile anymore and I cannot for the life of me figure out what the error message is trying to tell me!


Couldn't match expected type ‘[a] -> [a] -> [a]’
            with actual type ‘[b0]’
Relevant bindings include
  equal_els :: [a] -> [a] -> [a] (bound at ...)
In the expression: map fst $ filter (uncurry (==)) $ zip
In an equation for ‘equal_els’:
    equal_els = map fst $ filter (uncurry (==)) $ zip

Couldn't match expected type ‘[(b0, b0)]’
            with actual type ‘[a0] -> [b1] -> [(a0, b1)]’
Probable cause: ‘zip’ is applied to too few arguments
In the second argument of ‘($)’, namely ‘zip’
In the second argument of ‘($)’, namely
  ‘filter (uncurry (==)) $ zip’

Upvotes: 2

Views: 170

Answers (1)

awesoon
awesoon

Reputation: 33651

The type of $ is (a -> b) -> a -> b, so it accepts a function and an argument, and then passes the argument to the function.

You are trying to pass zip as a parameter, however, you should pass the result of zip function, i.e. combine two functions. This is the purpose of . (function composition):

Prelude> :t (.)
(.) :: (b -> c) -> (a -> b) -> a -> c

Prelude> let equal_els xs = map fst . filter (uncurry (==)) . zip xs
Prelude> equal_els [1, 2, 3] [1, 4, 3]
[1,3]

However, leaving the last element makes this function unreadable:

Prelude> let equal_els xs =       map fst . filter (uncurry (==))  .  zip   xs
Prelude> let equal_els xs =  (.) (map fst . filter (uncurry (==)))   (zip   xs)
Prelude> let equal_els xs = ((.) (map fst . filter (uncurry (==)))) . zip $ xs
Prelude> let equal_els    = ((.) (map fst . filter (uncurry (==)))) . zip

So, I'd leave the function with one parameter.

Upvotes: 3

Related Questions