为什么这个点自由定义在 Haskell 中不起作用?

Why does this point free definition not work in Haskell?

我试着做了以下函数定义:

relativelyPrime x y = gcd x y == 1

免分:

relativelyPrime = (== 1) . gcd

但是,这给了我以下错误:

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

不太明白。 gcd 接受两个 Ints/Integer,returns 一个 Ints/Integer,然后检查那个 Int/Integer 是否等于“1”。我看不出我的错误在哪里。

正如您评论的那样 - 如果您真的想要一个无点版本,您可以先使用 uncurry gcdgcd 转换为接受单个输入(元组)的版本:

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

然后用 (== 1) 检查,最后 curry 再次检查原始签名:

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

你的版本不起作用只是因为 gcd 如果只给定第一个参数就产生一个函数,这对于等待数字的 (== 1) 来说不是合法的输入。

它不起作用,因为 gcd 需要两个输入,而函数组合只提供 gcd 一个输入。考虑函数组合的定义:

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

因此,表达式 (== 1) . gcd 等价于:

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

这不是你想要的。你想要:

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

您可以定义一个新的运算符来组合一个一元函数和一个二元函数:

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

那么,你的表情就变成了:

relativelyPrime = (== 1) .: gcd

其实(.:)运算符可以按照函数组合来定义:

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

看起来有点像owl,但它们确实是等价的。因此,表达式的另一种写法:

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

如果您想了解发生了什么,请参阅:What does (f .) . g mean in Haskell?