Оптимизатор Haskell использует memoization для повторных вызовов функций в области?

Рассмотрим эту функцию:

f as = if length as > 100 then length as else 100

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

f as = 
  let l = length as
  in if l > 100 then l else 100

Если это так, то какой уровень настройки позволяет? Если это не так, то почему? В этом случае отходы памяти не могут быть причиной, описанной в этом ответе, поскольку введенная переменная освобождается после завершения выполнения функции.


Обратите внимание, что это не дубликат этого вопроса из-за локальной области видимости и, следовательно, может иметь принципиально иной ответ.

Ответ 1

GHC теперь делает несколько CSE по умолчанию, поскольку флаг -fcse включен.

Вкл. по умолчанию.. Включает устранение общего суб-выражения оптимизация. Выключение этого параметра может быть полезно, если у вас есть небезопасные выраженияPerformIO, которые вы не хотите распространять.

Тем не менее, он консервативен из-за проблем с внедрением совместного использования (и, следовательно, утечки пространства). Пропуск CSE получает бит лучше, хотя (и this).

Наконец, обратите внимание, что есть плагин для полной CSE.

Если у вас есть код, который может извлечь из этого выгоду.

Ответ 2

Даже в такой локальной настройке все же неясно, что введение совместного использования всегда является оптимизацией. Рассмотрим пример определения

f = if length [1 .. 1000000] > 0 then head [1 .. 1000000] else 0

против. этот

f = let xs = [1 .. 1000000] in if length xs > 0 then head xs else 0

и вы обнаружите, что в этом случае первое ведет себя намного лучше, так как каждый из вычислений, выполненных в списке, является дешевым, тогда как вторая версия приведет к тому, что список будет полностью развернут в памяти на length, и его можно отбросить только после уменьшения head.