6

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.

Ben
  • 1,561
  • 4
  • 21
  • 33
  • 4
    well `gcd` there will produce another function if given only one argument - and in your point-free version you hand this *function* on to `(== 1)` which of course does not know how to handle functions ;) – Random Dev Oct 11 '15 at 19:32
  • 2
    maybe you understand when you first *remove* one *point* : `relativePrime x = (== 1) . gcd x` this works! Now you cannot *remove* `x` anymore as it is *tied* to fast to `gcd` - you could if you had `(== 1) $ gcd x` – Random Dev Oct 11 '15 at 19:34
  • 1
    @Carsten's comment is correct. One option would be to use `uncurry` to turn `gcd` into a single-argument function (taking a tuple of two integers). – psmears Oct 11 '15 at 19:35
  • @psmears exactly `curry ((== 1) . (uncurry gcd))` should work ... but really IMO now point-free is point-less as the original version was easy to read and understand - this one is cluttered with useless parts just to make it point-free – Random Dev Oct 11 '15 at 19:37
  • @Carsten It does work indeed and I understand my error now. Feel free to expand this into an answer, since I think it deserves an up vote and accepted answer mark. Thanks! – Ben Oct 11 '15 at 19:39

2 Answers2

7

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?

Community
  • 1
  • 1
Aadit M Shah
  • 72,912
  • 30
  • 168
  • 299
5

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.

Random Dev
  • 51,810
  • 9
  • 92
  • 119