9

我知道

$ :: (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

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

4

3 回答 3

16

这与解析有关。在 Haskell 中,您可以编写(op arg)whereop是中缀运算符。这与((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)).

于 2013-04-03T10:42:06.690 回答
10

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

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

于 2013-04-03T10:30:51.927 回答
6

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

部分让您向二元运算符提供一个参数并生成一个函数 - 一个等待剩余参数的函数。

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

于 2013-04-03T10:30:50.393 回答