Search code examples
haskellpointfree

Why does this point free definition not work in Haskell?


I tried to make the following function definition:

relativelyPrime x y = gcd x y == 1

point-free:

relativelyPrime = (== 1) . gcd

However, this gives me the following error:

Couldn't match type ‘Bool’ with ‘a -> Bool’
Expected type: (a -> a) -> a -> Bool
  Actual type: (a -> a) -> Bool
Relevant bindings include
  relativelyPrime :: a -> a -> Bool (bound at 1.hs:20:1)
In the first argument of ‘(.)’, namely ‘(== 1)’
In the expression: (== 1) . gcd
In an equation for ‘relativelyPrime’:
    relativelyPrime = (== 1) . gcd

I don't quite understand. gcd takes two Ints/Integer, returns one Ints/Integer, then that one Int/Integer is checked for equality to '1'. I don't see where my error is.


Solution

  • It doesn't work because gcd requires two inputs whereas function composition only provides gcd one input. Consider the definition of function composition:

    f . g = \x -> f (g x)
    

    Hence, the expression (== 1) . gcd is equivalent to:

    \x -> (== 1) (gcd x)
    

    This is not what you want. You want:

    \x y -> (== 1) (gcd x y)
    

    You could define a new operator to compose a unary function with a binary function:

    f .: g = \x y -> f (g x y)
    

    Then, your expression becomes:

    relativelyPrime = (== 1) .: gcd
    

    In fact, the (.:) operator can be defined in terms of function composition:

    (.:) = (.) . (.)
    

    It looks kind of like an owl, but they are indeed equivalent. Thus, another way to write the expression:

    relativelyPrime = ((== 1) .) . gcd
    

    If you want to understand what's happening then see: What does (f .) . g mean in Haskell?