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

Ben*_*Ben 6 haskell pointfree

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

relativelyPrime x y = gcd x y == 1
Run Code Online (Sandbox Code Playgroud)

点免费:

relativelyPrime = (== 1) . gcd
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

我不太明白.gcd取两个Ints/Integer,返回一个Ints/Integer,然后检查一个Int/Integer是否等于'1'.我没看到我的错误在哪里.

Aad*_*hah 7

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

f . g = \x -> f (g x)
Run Code Online (Sandbox Code Playgroud)

因此,表达式(== 1) . gcd相当于:

\x -> (== 1) (gcd x)
Run Code Online (Sandbox Code Playgroud)

这不是你想要的.你要:

\x y -> (== 1) (gcd x y)
Run Code Online (Sandbox Code Playgroud)

您可以定义一个新运算符来组成具有二元函数的一元函数:

f .: g = \x y -> f (g x y)
Run Code Online (Sandbox Code Playgroud)

然后,你的表达式变为:

relativelyPrime = (== 1) .: gcd
Run Code Online (Sandbox Code Playgroud)

实际上,(.:)运算符可以根据函数组成来定义:

(.:) = (.) . (.)
Run Code Online (Sandbox Code Playgroud)

它看起来有点像猫头鹰,但它们确实相当.因此,编写表达式的另一种方法是:

relativelyPrime = ((== 1) .) . gcd
Run Code Online (Sandbox Code Playgroud)

如果你想了解发生了什么,那么请看:(f.).在Haskell中意味着什么?


Car*_*ten 5

当你评论它时 - 如果你真的想要一个无点版本,你可以先用它uncurry gcd来转换gcd成一个接受单个输入(一个元组)的版本:

Prelude> :t uncurry gcd
uncurry gcd :: Integral c => (c, c) -> c
Run Code Online (Sandbox Code Playgroud)

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

relativeelyPrime = curry ((== 1) . (uncurry gcd))
Run Code Online (Sandbox Code Playgroud)

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