Почему полная лень оптимизация по умолчанию?

Полная лень была несколько раз продемонстрировано в причина пространство утечки.

Почему полная лень от -O и дальше? Я не убежден в рассуждениях в SPJ Реализация языков функционального программирования. Утверждение состоит в том, что в

f = \y -> y + sqrt 4

sqrt 4 излишне повторяется каждый раз, когда вводится f, поэтому мы должны плавать за пределами лямбда. Я согласен в малом, но, поскольку мы видели, какие проблемы это преобразование вызывает в целом, я не верю, что это того стоит. Мне кажется, что преимущества этого преобразования можно получить в одностороннем порядке ** только с локальными изменениями кода, а программисты, которые этого хотят, должны реализовать его вручную.

Можете ли вы убедить меня иначе? Действительно ли full-laziness действительно полезен? Я буду особенно убежден, если вы можете привести примеры, которые для осуществления вручную потребуют многостороннего сотрудничества или нелокальных преобразований.

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

Ответ 1

Там, по крайней мере, один общий случай, когда полная лень "безопасна" и оптимизирована.

g :: Int -> Int
g z = f (z+1)
  where f 0 = 0
        f y = 1 + f (y-1)

Это действительно означает g = \z -> let {f = ...} in f (z+1) и, скомпилированный таким образом, будет выделять закрытие для f перед его вызовом. Очевидно, что это глупо, и компилятор должен преобразовать программу в

g_f 0 = 0
g_f y = 1 + g_f (y-1)
g z = g_f (z+1)

если для вызова g_f не требуется выделение. К счастью, полная трансформация лени делает именно это.

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

Другой пример:

h :: [Int] -> [Int]
h xs = map (+1) xs

В этом случае вы можете просто уменьшить эту сумму, но обычно вы не можете уменьшить ее. Именование функции (+1) довольно уродливо.