Ленивая оценка - это общее свойство чисто функциональных языков программирования, позволяющее «вернуть производительность», оно работает довольно просто, вы можете вычислять выражение только тогда, когда вам это нужно. Например, рассмотрим в Haskell
if x == 1 then x + 3 else x + 2
В строгой (нетерпеливой) оценке, если x действительно равен двум, то x + 3 вычисляется и возвращается, иначе x + 2, в Haskell такого не происходит, x + 3 просто составляется в выражение, например, скажем, у меня есть:
let x = if x == 1 then x + 3 else x + 2
Хорошо, тогда я сохраняю это в переменной, но что, если я никогда не буду когда-либо когда-либо использовать эту переменную из-за некоторых других условий? Я потратил впустую очень дорогое целочисленное дополнение на своем процессоре. (хорошо, на практике вы не выигрываете в этом, но вы получаете идею с большими выражениями)
Тогда возникает вопрос, почему не все языки ленивы? Ну, в общем, простая причина в том, что в чисто функциональных языках выражения гарантированно не имеют побочных эффектов вообще. Если бы они имели, мы должны были бы оценить их в правильном порядке. Вот почему на большинстве языков они охотно оцениваются. В тех языках, где выражения не имеют побочных эффектов, в ленивых вычислениях нет риска, поэтому логичным выбором будет вернуть производительность, которую они склонны терять в других областях.
Еще один интересный побочный эффект заключается в том, что if-then-else в Haskell действительно является функцией типа Bool -> a -> a -> a
. В Haskell это означает, что он принимает один аргумент типа Boolean, другой аргумент типа any, другой тип того же типа, что и первый, и возвращает этот тип снова. Вы не сталкиваетесь с бесконечной оценкой различных ветвей управления, потому что значения оцениваются только тогда, когда они необходимы, что обычно происходит в самом конце программы, когда составлено огромное выражение, а затем оценивается для окончательного результата, отбрасывая все вещи, которые компилятор считает ненужными для конечного результата. Например, если я разделю чрезвычайно сложное выражение само по себе, оно может быть просто заменено на «1» без оценки обеих частей.
Различие видно в Схеме, которая традиционно строго оценивается, но есть ленивый вариант, называемый Ленивой Схемой, в Схеме (display (apply if (> x y) "x is larger than y" "x is not larger than y"))
является ошибкой, потому что if
не является функцией, это специализированный синтаксис (хотя некоторые скажем, синтаксис вообще не является особенным в Scheme), поскольку он не обязательно оценивает все его аргументы, иначе у нас не хватило бы памяти, если бы мы попытались, например, вычислить факториал. В Lazy Scheme это работает просто отлично, потому что ни один из этих аргументов не оценивается вообще, пока функции действительно не понадобится результат для продолжения оценки, например display.