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

时间:2015-10-11 19:29:50

标签: haskell pointfree

我尝试进行以下功能定义:

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,返回一个Ints / Integer,然后检查一个Int / Integer是否等于' 1'。我不知道我的错误在哪里。

2 个答案:

答案 0 :(得分:7)

它不起作用,因为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

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

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

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

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

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

答案 1 :(得分:5)

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

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

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

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

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