为什么Haskell中的函数组合是正确的?

Aad*_*hah 32 haskell associativity function-composition

数学上,函数组合操作是关联的.因此:

f . (g . h) = (f . g) . h
Run Code Online (Sandbox Code Playgroud)

因此,功能组合操作可以被定义为左关联或右关联.

由于Haskell中的正常函数应用(即术语的并置,而不是$操作)在我看来是左联想的,因此函数组合也应该是左联的.毕竟世界上大多数人(包括我自己)习惯于从左到右阅读.

然而,Haskell中的函数组合是正确的关联:

infixr 9 .
Run Code Online (Sandbox Code Playgroud)

我知道函数组合操作是左关联还是右关联并没有什么区别.尽管如此,我很想知道它为什么不留下联想.我想到这个设计决定有两个原因:

  1. Haskell的制造商希望功能组合在逻辑上与$操作类似.
  2. Haskell的制造者之一是日本人,他发现使函数组合成为正对联而不是左联合更直观.

除了笑话,在Haskell中,函数组合是否存在正确联想是否有任何有益的理由?如果Haskell中的函数组合是左对联的,它会有什么不同吗?

Car*_*arl 37

在存在非严格评估的情况下,权利关联是有用的.让我们看一个非常愚蠢的例子:

foo :: Int -> Int
foo = const 5 . (+3) . (`div` 10)
Run Code Online (Sandbox Code Playgroud)

好的,当这个函数在0时.被评估时会发生infixr什么?

foo 0
=> (const 5 . ((+3) . (`div` 10))) 0
=> (\x -> const 5 (((+3) . (`div` 10)) x)) 0
=> const 5 (((+3) . (`div` 10)) 0)
=> 5
Run Code Online (Sandbox Code Playgroud)

现在,如果.是的话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
Run Code Online (Sandbox Code Playgroud)

(我有点累.如果我在这些减少步骤中犯了任何错误,告诉我,或者只是解决它们......)

他们有相同的结果,是的.但减少步骤的数量并不相同.当.左关联时,合成操作可能需要减少更多次 - 特别是,如果链中较早的函数决定快捷方式,使得它不需要嵌套计算的结果.最糟糕的情况是相同的,但在最好的情况下,权利相关性可能是一个胜利.所以选择有时更好的选择,而不是有时更糟糕的选择.

  • 从本质上讲,你要将控制权交给链中最左边的函数,并且你想尽快做到这一点,所以你把其余部分组合在一起. (5认同)
  • @max通过减少图来进行Haskell代码的评估。减少步骤是运行时。 (3认同)