为什么Haskell中的函数组合是右结合的?

34

从数学上讲,函数组合操作是结合的。因此:

f . (g . h) = (f . g) . h
因此,函数组合操作可以定义为左结合或右结合。
由于在Haskell中的普通函数应用(即项的临近,而不是$ 操作),在我看来函数组合也应该是左结合的。毕竟,大多数人(包括我自己)习惯从左到右阅读。
尽管如此,在Haskell中,函数组合是右结合的:
infixr 9 .

我知道函数复合运算符是左结合还是右结合并不真正有什么区别。但我很好奇为什么它不是左结合的。这个设计决策有两个原因:

  1. Haskell 的创作者希望函数复合在逻辑上与 $ 操作类似。
  2. Haskell 的其中一位创作者是日本人,他认为把函数复合定义为右结合比左结合更加直观自然。

开玩笑的话先放一边,那么函数复合在 Haskell 中设置成右结合是否有任何有益的原因?如果 Haskell 中的函数复合是左结合的,会有什么不同吗?


5
有一派人认为右结合是“完全错误的”。(链接指向参考资料,无需翻译) - Don Stewart
2
查看完整线程 - Don Stewart
有趣的阅读。我同意,$ 操作符没有理由是右结合的。然而,右结合并不总是错误的。例如,++ 操作符和逻辑操作符 &&|| 必须明显地是右结合的,以便连接成本最小化,并且逻辑表达式可以被短路。 - Aadit M Shah
4
好的,"$"不是可结合的。如果将它改成"infixl"定义,它会具有不同的语义。而那些不同的语义可能会更好。但由于"."是可结合的,所以无论哪种方式语义都是相同的——唯一改变的是操作细节,在这方面,使用"infixr"肯定更好。 - Carl
2
不幸的是,由于参数在函数之后,数据从右向左流动。 - Sassa NF
@Carl Ah,我现在明白了。你的回答非常有见地。谢谢。=) - Aadit M Shah
1个回答

43

在存在非严格求值的情况下,右结合很有用。让我们看一个非常愚蠢的例子:

foo :: Int -> Int
foo = const 5 . (+3) . (`div` 10)

好的,当.infixr时,这个函数在0处求值会发生什么?

foo 0
=> (const 5 . ((+3) . (`div` 10))) 0
=> (\x -> const 5 (((+3) . (`div` 10)) x)) 0
=> const 5 (((+3) . (`div` 10)) 0)
=> 5

现在,如果.infixl呢?

foo 0
=> ((const 5 . (+3)) . (`div` 10)) 0
=> (\x -> (const 5 . (+3)) (x `div` 10)) 0
=> (const 5 . (+3)) (0 `div` 10)
=> (\x -> const 5 (x + 3)) (0 `div` 10)
=> const 5 ((0 `div` 10) + 3)
=> 5

我有点累了。如果我在这些化简步骤中犯了任何错误,请让我知道,或者直接修复它们。

是的,它们有相同的结果。但是化简步骤的数量不同。当 . 是左结合时,组合操作可能需要进行更多次化简 - 特别是,如果链条中较早的函数决定捷径以便它不需要嵌套计算的结果。最坏情况是相同的,但是在最好的情况下,右结合性可能会胜出。因此,选择有时更好的选择,而不是有时更差的选择。


8
基本上,你要将控制权移交给链中最左边的函数,并且希望尽早这样做,因此你要将其余的函数捆绑在一起。 - Ben Millwood
6
Haskell代码的评估通过图形减少进行。减少步骤是在运行时进行的。 - Carl
@codeshot 函数组合是可结合的。你提出的例子是一个问题,因为其他一些不可结合的运算符与它共享优先级。这并不是 (.) 的固定性的问题。由于函数组合是可结合的,当链式使用时,应始终以更高效的方式解析。故此事已了结。现在,如果你想说它应该有一个不同于 9 的优先级,你可能可以提出一个合理的论点。 - Carl
另一个运算符是以 (.) 开始的家族中的第二个,它们都可以提供更有效的通信,如果它们都是 infixl 的话,但是给它们不同的优先级并不能解决通信问题。这种效率问题可以通过计算机擅长的多种方式来解决,但有效的通信问题只有相对较少的解决方案。 - codeshot
我不想增加复杂性,但如果这是为了保持整个软件开发系统简单(我们必须始终考虑的更大事情),那么复杂性必须以最适当的方式共享,因为每个规模都有最小的复杂性,我们必须试图通过在过度不平衡时移动它来在所有规模中找到低复杂性。这是这种不平衡的情况。infixr 的实际测量影响是什么?每个使用两个相邻组合的表达式在整个程序执行期间会多出一对步骤一次吗? - codeshot
显示剩余4条评论

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