【发布时间】:2013-10-31 12:32:42
【问题描述】:
当您编写稍微复杂一点的函数时,我注意到$ 被大量使用,但我不知道它的作用是什么?
【问题讨论】:
-
这是“应用”运算符。这个博客在介绍它的基础方面做得很好:snakelemma.blogspot.com/2009/12/dollar-operator-in-haskell.html
标签: haskell syntax operators dollar-sign
当您编写稍微复杂一点的函数时,我注意到$ 被大量使用,但我不知道它的作用是什么?
【问题讨论】:
标签: haskell syntax operators dollar-sign
$ 是中缀“应用程序”。它被定义为
($) :: (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]
【讨论】:
f . g . h $ x,也可能是(f . g . h) x。
$的定义有点假。 GHC 实际上将其视为语法,以便 runST $ do 成语起作用(除了在它真正是函数的部分之外)。它应该只是一个函数,但更高级别的类型是一个问题。
<$> 只是中缀fmap。据我所知,它并没有什么特别之处。
我喜欢将 $ 符号视为括号的替代品。
例如下面的表达式:
take 1 $ filter even [1..10]
-- = [2]
如果我们不放 $ 会发生什么?然后我们会得到
take 1 filter even [1..10]
编译器现在会抱怨,因为它会认为我们正在尝试将 4 个参数应用于 take 函数,参数为 1 :: Int、filter :: (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]
【讨论】:
$ 符号时,否则为行尾。