Haskell中的$符号是什么意思/作用?

67
当你编写稍微复杂一些的函数时,我注意到经常使用$,但我不知道它是干什么用的?

这是"apply"运算符。这篇博客在介绍它的基本概念方面做得还不错:http://snakelemma.blogspot.com/2009/12/dollar-operator-in-haskell.html - vcsjones
4
反向去重。 - Shoe
2个回答

80

$是中缀运算符“应用”。它的定义是

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

-- or 
($) f x = f x
-- or
($) = id

这对于避免额外的括号非常有用:f (g x) == f $ g x

它特别适用于“尾随 lambda 体”这样的情况。

forM_ [1..10] $ \i -> do
  l <- readLine
  replicateM_ i $ print l

相对于

forM_ [1..10] (\i -> do
  l <- readLine
  replicateM_ i (print l)
)

或者,更巧妙的是,当表达“将此参数应用于任何函数”时,有时会分成几个部分显示。
applyArg :: a -> (a -> b) -> b
applyArg x = ($ x)

>>> map ($ 10) [(+1), (+2), (+3)]
[11, 12, 13]

5
是的。有时也会写成 f . g . h $ x,这也可以表示为 (f . g . h) x - J. Abrahamson
5
技术笔记:据我所知,目前 $ 的定义有点不准确。在 GHC 中,它实际上被视为语法,这样 runST $ do 这种习惯用法才能工作(除了像 sections 这样真正是函数的地方)。本应该只是一个函数,但高阶类型是个问题。 - Philip JF
3
值得一提的是,除了运算符的特征之外,它的优先级为0。因此,所有的运算都比$更紧密地绑定。 - JohnL4
我认为你第一行的分组是不正确的。:t($) :: (a -> b) -> a -> b - johnbakers
显示剩余3条评论

30

我喜欢把美元符号看作是括号的替代。

例如,下面的表达式:

take 1 $ filter even [1..10] 
-- = [2]
如果我们不放置“$”符号,会发生什么?那么我们将得到:

如果我們沒有放置“$”符號,會發生什麼?那麼我們將得到:

take 1 filter even [1..10]

现在编译器会报错,因为它会认为我们试图将4个参数应用于take函数,这些参数分别是1 :: Intfilter :: (a -> Bool) -> [a] -> [a]even :: Integral a => a -> Bool[1..10] :: [Int]

这显然是错误的。那么我们可以怎么做呢?嗯,我们可以在表达式周围加上括号:

(take 1) (filter even [1..10])

这样就变成了:

(take 1) ([2,4,6,8,10])

然后就变成了:

take 1 [2,4,6,8,10]

但是我们并不总想写括号,特别是当函数开始嵌套时。一种替代方法是在一对括号应该放置的地方之间放置$符号,比如在这种情况下是:

take 1 $ filter even [1..10]


编译器如何推断括号的结尾位置? - user12530264
1
当它找到下一个$符号或者行尾时。 - Dhia

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接