在Haskell中,我经常使用 $ 符号编写表达式。我发现它很自然和易读,但有时我会读到说这是坏习惯,而我不明白为什么应该这样说。
foo = bar . baz . quux
foo x = bar . baz . quux $ x
foo x = (bar . baz . quux) x
foo x = bar (baz (quux x))
我按照自己的偏好粗略排序了它们,尽管口味因人而异,而且情境可能需要不同的选择。我还偶尔看到
foo = bar
. baz
. quux
当bar
、baz
和quux
子表达式都很长时,以下写法是不好的:
foo x = bar $ baz $ quux $ x
这种写法不太好的原因有两个。第一个是在重构时无法复制和粘贴较少的子表达式到辅助定义中;对于所有的($)
操作符,只有包含x
参数的子表达式才是有效的重构,而对于(.)
和($)
操作符,甚至像bar . baz
或baz . quux
这样的子表达式也可以被提取出来放到单独的定义中。
第二个选择(.)
的原因是为了预防($)
的优先级可能会发生变化;目前,($)
的优先级为infixr
,意味着它右结合,就像这样:
foo x = bar $ (baz $ (quux $ x))
然而,如果($)
是infixl
的话,在更多的表达式中它将会非常有用;例如:
foo h = f (g x) (h y)
foo h = f $ g x $ h y
foo h = (f $ g x) $ h y
...现在无法不使用括号表示。 "不良格式"的例子,如果使用infixl
应用程序解析,将会是:
foo x = ((bar $ baz) $ quux) $ x
这意味着有着显著不同的含义。因此,通过避免使用这种形式来保证您的代码具有未来的可扩展性。
bar . baz $ quux x
或 bar (baz . quux $ x)
这样的东西,通常在涉及其他中缀运算符或强调特定函数应用程序的情况下出现。 - C. A. McCannbar $ baz $ quux $ x
,这等同于 bar . baz . quux $ x
。当然,我们鼓励使用后者而不是前者。 - Dan Burton$
的优先级或固定性会改变 - $
的重点是要具有低优先级,而且你无法比0更低,所以f $ g $ h x
是可以的。个人不喜欢用 f . g . h $ x
,因为它使用了两个操作符(因此涉及两个概念——组合和应用),而 $
表单则只使用了一个。 - stephen tetley($)
的结合性可能会改变更清晰吗?正如你所说,优先级水平恰到好处。 - Daniel Wagner