Haskell中的$是什么,以及如何将函数应用于函数

Kir*_*rst 1 haskell function operator-precedence

我正在使用Haskell进行Project Euler,并在完成第一个问题时找到了要学习的东西.这是我的代码:

isValid x = (mod x 3 == 0) || (mod x 5 == 0)
listValid :: Integer -> [Integer]
listValid n = [x | x <- [1..n-1], isValid x]
Run Code Online (Sandbox Code Playgroud)

该函数listValid将获得所有正整数小于n可被3或5分解的正整数.足够简单.

*Main> listValid 10
[3,5,6,9]
Run Code Online (Sandbox Code Playgroud)

现在我需要总结它们.我认为sum函数是正确的方法.我不明白为什么前两个版本工作,然后第三个不工作.

*Main> sum (listValid 10)
23
*Main> sum $ listValid 10
23
*Main> sum listValid 10

<interactive>:4:5:
    Couldn't match type ‘[Integer]’ with ‘a0 -> t’
    Expected type: Integer -> a0 -> t
      Actual type: Integer -> [Integer]
    Relevant bindings include it :: t (bound at <interactive>:4:1)
    In the first argument of ‘sum’, namely ‘listValid’
    In the expression: sum listValid 10
Run Code Online (Sandbox Code Playgroud)

这是一个操作顺序问题,我需要用括号括起来断言应该首先应用哪个函数?如果是$这样,第二个版本的做法是什么?

sep*_*p2k 5

这是关于关联性的.函数应用程序是左关联的,所以sum listValid 10相当于(sum listValid) 10,而不是sum (listValid 10).如果你考虑一下,就必须这样:如果你定义add x y = x+y,你就不希望add 1 2等同于add (1 2).

所以这里的问题是sum listValid 10,它不会被listValid 10视为参数sum; 它将其listValid视为参数sum,然后10视为参数sum listValid.

$解决了这个问题,因为它是一个中缀运算符,并且非常清楚它sum是左操作数并且listValid 10是它的右操作数(请记住,函数应用程序的优先级高于任何中缀运算符,所以它不能被视为(sum $ listValid) 10).