2013-12-03 8 views
23

Математически операция композиции функций ассоциативна. Следовательно:Почему функция композиция в Haskell право ассоциативной?

f . (g . h) = (f . g) . h 

Таким образом, операцию композиции функции можно определить как левую ассоциативную, так и правую ассоциативную.

Поскольку нормальное применение функции в Haskell (то есть сопоставление терминов, а не операция $) остается ассоциативным, по моему мнению, композиция функций также должна быть ассоциативной. Ведь большинство людей в мире (включая меня) используются для чтения слева направо.

Тем не менее композиция функций в Haskell является правильным ассоциативным:

infixr 9 . 

Я знаю, что это на самом деле не делает разницы ли операция композиции функций левоассоциативно или справа ассоциативно. Тем не менее мне любопытно узнать, почему это не осталось ассоциативным. Две причины приходят на мой взгляд, для этого дизайнерского решения:

  1. Создатели Haskell хотели композиция функций логически похожа, как в $ операции.
  2. Одним из создателей Haskell был японский, который счел более интуитивно понятным, чтобы композиция композиции была правильной ассоциативной, а не левой ассоциативной.

Шутки в сторону, есть ли какая-либо полезная причина для того, чтобы композиция функций была правильной ассоциативной в Haskell? Будет ли иметь значение, если состав композиции в Haskell остался ассоциативным?

+5

Существует лагерь, в котором утверждается, что право-ассоциативность (просто неверно) (http://www.mail-archive.com/[email protected]/msg12549.html) –

+2

См. [Полная версия ] (http://www.mail-archive.com/[email protected]/msg12528.html) –

+0

Интересное чтение. Я согласен, нет никакой причины, чтобы операция '' 'была правильной ассоциативной. Однако правильная ассоциативность не всегда ошибается.Например, операция '' '' '' '' '' '' '' '' '' '' '' '' '' '' 'должна быть правильно ассоциативной, так что стоимость конкатенации минимальна и поэтому логические выражения могут быть закорочены соответственно. –

ответ

29

При наличии нестрогой оценки правильная ассоциативность полезна. Давайте посмотрим на очень тупой пример:

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

Хорошо, что происходит, когда эта функция оценивается в 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 

Теперь, что если . был 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 

(я вроде устал. Если бы я сделал какую-то ошибку в этих мерах по сокращению пожалуйста дайте мне знать, или просто исправить их ..)

Они имеют один и тот же результат, да. Но количество шагов восстановления не одинаково. Когда . является лево-ассоциативным, операцию композиции, возможно, нужно уменьшить в несколько раз - в частности, если функция, ранее существовавшая в цепочке, решает сделать так, чтобы она не нуждалась в результате вложенных вычислений. Худшие случаи одинаковы, но в лучшем случае право-ассоциативность может быть победой. Так что идите с выбором, который иногда лучше, вместо выбора, который иногда бывает хуже.

+4

По сути, вы собираетесь передать управление самой левой функции в цепочке, и вы хотите сделать это как можно скорее, чтобы вы собрали остальных вместе. –

+0

Правильно ли я понимаю, что только количество шагов * сокращения * отличается от других; количество шагов * оценки * одинаково в обоих случаях? Другими словами, время выполнения (после компиляции кода) будет одинаковым для 'infixr' и' infixl', но компиляция выполняется быстрее для 'infixr'? – max

+1

@max Оценка кода Haskell продолжается путем уменьшения графика. Шаги сокращения - это время выполнения. – Carl