实际上$功能在haskell中做了什么?

时间:2013-04-03 10:25:45

标签: haskell syntax operators dollar-sign haskell-prelude

我知道

$ :: (a->b) -> a -> b
f $ x = f x

直觉上,在我看来,喜欢说, 1. $将功能评估推迟到左侧 2.评估其权利 3.将其左侧的结果输入右侧。

这对我来说非常有意义,

ghci> length $ [1..5]
5
ghci> ($) length [1..5]
5

我不明白为什么,

ghci> ($ [1..5]) length
5

从$的类型判断,是不是它的(第一个)参数应该是一个函数?

3 个答案:

答案 0 :(得分:16)

这与解析有关。在Haskell中,您可以编写(op arg),其中op是一个中缀运算符。这与((op) arg)不同。你也可以写(arg op)!例如:

GHCi, version 7.0.3: http://www.haskell.org/ghc/  :? for help
Prelude> :t (+ 4)
(+ 4) :: Num a => a -> a
Prelude> :t (4 +)
(4 +) :: Num a => a -> a

也就是说,(+ 4)是函数\x -> x + 4(4 +)是函数\y -> 4 + y。在添加的情况下,这些功能相同,但现在这并不重要。

现在让我们在$上尝试相同的技巧:

Prelude> :t ($ [1,2,3,4])
($ [1,2,3,4]) :: Num t => ([t] -> b) -> b

到目前为止,我们得到了\f -> f $ [1,2,3,4]。我们也可以写

Prelude> :t (length $)
(length $) :: [a] -> Int

获取函数\l -> length $ l。但是这个怎么样:

Prelude> :t ($ length)
($ length) :: (([a] -> Int) -> b) -> b

这很奇怪,但这很有道理!我们得到了\f -> f $ length,即功能,它希望获得一个f类型([a] -> Int) -> b)的函数,该函数将应用于length。还有第四种可能性:

Prelude> :t ([1,2,3,4] $)

<interactive>:1:2:
    Couldn't match expected type `a0 -> b0' with actual type `[t0]'
    In the first argument of `($)', namely `[1, 2, 3, 4]'
    In the expression: ([1, 2, 3, 4] $)

一切都是应有的,因为[1,2,3,4]不是一个功能。如果我们在括号中写$怎么办?然后它作为中缀运算符的特殊含义消失了:

Prelude> :t (($) length)
(($) length) :: [a] -> Int

Prelude> :t (($) [1,2,3,4])
<interactive>:1:6:
    Couldn't match expected type `a0 -> b0' with actual type `[t0]'
    In the first argument of `($)', namely `[1, 2, 3, 4]'
    In the expression: (($) [1, 2, 3, 4])

Prelude> :t (length ($))
<interactive>:1:9:
    Couldn't match expected type `[a0]'
                with actual type `(a1 -> b0) -> a1 -> b0'
    In the first argument of `length', namely `($)'
    In the expression: (length ($))

Prelude> :t ([1,2,3,4] ($))
<interactive>:1:2:
    The function `[1, 2, 3, 4]' is applied to one argument,
    but its type `[t0]' has none
    In the expression: ([1, 2, 3, 4] ($))

因此,要回答您的问题:$ [1,2,3,4]被解析为\f -> f $ [1,2,3,4],因此将其应用于length非常有意义。但是($) [1, 2, 3, 4]没有多大意义,因为($)不被视为中缀运算符。

顺便说一下,$做“什么都不做”,可以这么说。它主要用于更易读的输入,因为它的优先级较低,因此我们可以编写f $ g $ h $ x而不是f (g (h x))

答案 1 :(得分:10)

您的问题实际上是关于所谓的运算符部分。对于Haskell中的任何运算符(我将使用+作为示例),您可以编写类似(+ arg)(arg +)的内容。这些只是匿名函数(\x -> x + arg)(\x -> arg + x)的简写语法。

因此,($ [1..5])语法只意味着(\x -> x $ [1..5])(\x -> x [1..5])相同(即将[1..5]传递给作为其参数传递的函数的函数)。

答案 2 :(得分:6)

($ [1..5])是一个部分。这是一个部分应用的运算符。这是(\f -> f $ [1..5])的简写。

Sections允许您为二元运算符提供一个参数并生成一个函数 - 一个等待剩余参数的函数。

查看http://www.haskell.org/haskellwiki/Section_of_an_infix_operator