Ben
Ben

Reputation: 1581

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.

Upvotes: 6

Views: 199

Answers (2)

Aadit M Shah
Aadit M Shah

Reputation: 74244

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?

Upvotes: 7

Random Dev
Random Dev

Reputation: 52290

as you commented on it - if you really want a point-free version you can first use uncurry gcd to transform gcd into a version that accepts a single input (a tuple):

Prelude> :t uncurry gcd
uncurry gcd :: Integral c => (c, c) -> c

then check with (== 1) and finally curry it again for the original signature:

relativeelyPrime = curry ((== 1) . (uncurry gcd))

your version did not work just because gcd produces a function if given only the first argument and this is no legal input for (== 1) which awaits a number.

Upvotes: 5

Related Questions