【发布时间】:2010-09-28 14:26:22
【问题描述】:
根据我的阅读,$ 被描述为“将函数应用于其参数”。然而,它似乎不像 Lisp 中的 (apply ...) 那样工作,因为它是一个二元运算符,所以它看起来唯一的作用就是有时有助于避免括号,比如 foo $ bar quux 而不是 foo (bar quux)。我理解对了吗?后一种形式是否被认为是“坏风格”?
【问题讨论】:
根据我的阅读,$ 被描述为“将函数应用于其参数”。然而,它似乎不像 Lisp 中的 (apply ...) 那样工作,因为它是一个二元运算符,所以它看起来唯一的作用就是有时有助于避免括号,比如 foo $ bar quux 而不是 foo (bar quux)。我理解对了吗?后一种形式是否被认为是“坏风格”?
【问题讨论】:
您的理解基本正确——也就是说,大约 99% 的 $ 使用是为了帮助避免使用括号,是的,在大多数情况下,它似乎确实比括号更受欢迎。
请注意:
> :t ($) ($) :: (a -> b) -> a -> b也就是说,$是一个函数;因此,它可以被传递给函数,由它组成,以及任何你想用它做的事情。我想我以前见过有人用它来搞混组合器。
【讨论】:
$ 在左括号和右括号之间的距离大于良好的可读性保证时,或者如果您有多层嵌套括号时,首选括号。
例如
i (h (g (f x)))
可以改写
i $ h $ g $ f x
也就是说,它代表了右关联函数的应用。这很有用,因为普通函数应用程序关联到左侧,即以下
i h g f x
...可以改写如下
(((i h) g) f) x
($) 函数的其他方便用途包括使用它压缩列表:
zipWith ($) fs xs
这会将函数列表fs 中的每个函数应用于列表xs 中的相应参数,并将结果收集到列表中。与 sequence fs x 对比,它将函数列表 fs 应用于单个参数 x 并收集结果;和 fs <*> xs 将列表 fs 中的每个函数应用于列表 xs 的每个元素。
【讨论】:
($) 的文档回答了您的问题。不幸的是,它没有在automatically generated documentation of the Prelude 中列出。
但是它在源代码中列出,您可以在此处找到:
http://darcs.haskell.org/packages/base/Prelude.hs
但是这个模块没有直接定义 ($)。由前者导入的以下内容:
http://darcs.haskell.org/packages/base/GHC/Base.lhs
我在下面包含了相关代码:
infixr 0 $
...
-- | Application operator. This operator is redundant, since ordinary
-- application @(f x)@ means the same as @(f '$' x)@. However, '$' has
-- low, right-associative binding precedence, so it sometimes allows
-- parentheses to be omitted; for example:
--
-- > f $ g $ h x = f (g (h x))
--
-- It is also useful in higher-order situations, such as @'map' ('$' 0) xs@,
-- or @'Data.List.zipWith' ('$') fs xs@.
{-# INLINE ($) #-}
($) :: (a -> b) -> a -> b
f $ x = f x
【讨论】:
上面有很多很好的答案,但遗漏了一个:
$不能总是用括号代替
但是$ 的任何应用都可以用括号消除,($) 的任何应用都可以用id 代替,因为$ 是恒等函数。 (f$) 的使用可以被f 替换,但是像($x) 这样的使用(将函数作为参数并将其应用于x)在我看来没有任何明显的替换。
【讨论】:
如果我在这里查看您的问题和答案,Apocalisp 和您都是对的:
$ 优于括号在某些情况下(见他的回答)foo (bar quux) 风格肯定不错!另外,请查看difference between . (dot) and $ (dollar sign),另一个与您非常相关的 SO 问题。
【讨论】: