关于何时撰写以及何时使用$的困惑

时间:2018-11-15 17:18:35

标签: haskell

returnGreater :: (Ord a) => a -> a -> a
returnGreater a b
  | (a > b) = a
  | otherwise = b

returnGreatest2 :: (Ord a, Num a) => a -> a -> a -> (a, a)
returnGreatest2 a b c
  | (a > b) = (a, returnGreater b c)
  | otherwise = (b, returnGreater a c)

sumOfSquares :: (Num a) => (a, a) -> a
sumOfSquares (a, b) = a^2 + b^2

鉴于上述功能,我很困惑为什么let x = sumOfSquares . returnGreatest2返回

<interactive>:13:24: error:
    • Couldn't match type ‘a -> a -> (a, a)’ with ‘(c, c)’
      Expected type: a -> (c, c)
        Actual type: a -> a -> a -> (a, a)
    • Probable cause: ‘returnGreatest2’ is applied to too few arguments
      In the second argument of ‘(.)’, namely ‘returnGreatest2’
      In the expression: sumOfSquares . returnGreatest2
      In an equation for ‘x’: x = sumOfSquares . returnGreatest2
    • Relevant bindings include
        x :: a -> c (bound at <interactive>:13:5)

但是sumOfSquares $ returnGreatest2 3 5 7做正确的事。由于returnGreatest2产生的类型与sumOfSquares期望的类型相同,所以我认为我可以组成它们。

3 个答案:

答案 0 :(得分:5)

组成和咖喱可能会有些混乱。 sumOfSquares . returnGreatest2\x -> sumOfSquares (returnGreatest2 x)相同,但是returnGreatest2 x的类型为(Ord a, Num a) => a -> a -> (a, a)。在最终获得(Ord a, Num a) => (a, a)可以接受的sumOfSquares类型的值之前,您需要传递所有期望的参数。

另一方面,sumOfSquares $ returnGreatest2 3 5 7的解析与sumOfSquares $ (returnGreatest2 3 5 7)相同; ($)运算符的优先级比函数应用程序(或其他任何运算符)低。

要真正组合这两个功能,您需要多层组合:

let f = ((sumOfSquares .) . ) . returnGreatest2

答案 1 :(得分:4)

(.)函数的两侧都应为单个参数函数,因此它将returnGreatest2视为a -> (a -> a -> (a, a))。但是sumOfSquares不接受(a -> a -> (a, a))作为参数。一种实现方法是像以前一样使用$并应用所有参数,但是您也可以明确声明前两个参数:

let x a b = sumOfSquares . returnGreatest2 a b
x :: (Num c, Ord c) => c -> c -> c -> c

这样类型将匹配。

答案 2 :(得分:2)

您可以尝试

sumOfSquares . returnGreatest2 3 5 $ 7

$的优先级最低。 returnGreatest2 3 5是函数returnGreatest2的一部分,部分应用于35,因此仍然是一个接受单个变量的函数。因此,现在您有两个接受单个变量的函数:

  • sumOfSquares
  • returnGreatest2 3 5

您可以用.来构成它们,.的目的是:组合一个带有单个变量输入和一个单个变量输出的函数。