我知道
$ :: (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
从$的类型来看,它的(第一个)参数不应该是一个函数吗?
我知道
$ :: (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
从$的类型来看,它的(第一个)参数不应该是一个函数吗?
这与解析有关。在 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))
.
您的问题实际上是关于所谓的操作员部分。使用 Haskell 中的任何运算符(我将+
用作示例),您可以编写类似(+ arg)
or的内容(arg +)
。这些只是匿名函数(\x -> x + arg)
和的简写语法(\x -> arg + x)
,分别。
因此,($ [1..5])
语法只是意味着(\x -> x $ [1..5])
与(\x -> x [1..5])
(即传递[1..5]
给作为其参数传递的函数的函数)相同。
($ [1..5])
是一个部分。那是一个部分应用的运算符。它是 的简写(\f -> f $ [1..5])
。
部分让您向二元运算符提供一个参数并生成一个函数 - 一个等待剩余参数的函数。
看看http://www.haskell.org/haskellwiki/Section_of_an_infix_operator