C имеет концепцию точек последовательности , которые гарантируют для определенных операций, что один операнд будет оценен перед другим. Я думаю, что это наиболее близкая существующая концепция, но по существу эквивалентный термин точка строгости (или, возможно, точка силы ) больше соответствует мышлению Хаскелла.
На практике Haskell не является чисто ленивым языком: например, сопоставление с образцом, как правило, строгое (поэтому попытка сопоставления с образцом вынуждает вычисление происходить, по крайней мере, достаточно далеко, чтобы принять или отклонить совпадение.
& hellip;
Программисты также могут использовать примитив seq
для принудительного вычисления выражения независимо от того, будет ли когда-либо использоваться результат.
$!
определяется как seq
.
- Ленивый против нестрогого .
Так что ваше мышление о !
/ $!
и seq
по существу правильно, но сопоставление с образцом подчиняется более тонким правилам. Конечно, вы всегда можете использовать ~
для принудительного сопоставления с образцом. Интересный момент из той же статьи:
Анализатор строгости также ищет случаи, когда подвыражения всегда требуются внешним выражением, и преобразует их в нетерпеливую оценку. Это может быть сделано, потому что семантика (в терминах «дна») не меняется.
Давайте продолжим по кроличьей норе и посмотрим на документы для оптимизации, выполненной GHC:
Анализ строгости - это процесс, с помощью которого GHC пытается во время компиляции определить, какие данные определенно «всегда будут необходимы». Затем GHC может создать код для простого вычисления таких данных, а не обычный процесс (с большими накладными расходами) для сохранения вычисления и его последующего выполнения.
- Оптимизация GHC: анализ строгости .
Другими словами, строгий код может быть сгенерирован в любом месте в качестве оптимизации, потому что создание блоков неоправданно дорого, когда данные всегда будут нужны (и / или могут использоваться только один раз).
& hellip; больше оценки невозможно выполнить для значения; говорят, что он находится в нормальной форме . Если мы находимся на каком-либо из промежуточных этапов, чтобы выполнить хотя бы некоторую оценку значения, оно находится в нормальной форме слабой головы (WHNF). (Существует также «нормальная форма головы», но она не используется в Haskell.) Полная оценка чего-либо в WHNF сводит его к чему-то в нормальной форме & hellip;
& mdash; Wikibooks Haskell: Лень
(Термин в нормальной форме головы , если в положении головы нет бета-переопределения 1 . Редекс - это пересмотр головы, если он предшествуют только лямбда-абстракционеры не переопределения 2 .) Поэтому, когда вы начинаете форсаж, вы работаете в WHNF; когда не осталось громов, чтобы быть в силе, вы в нормальной форме. Еще один интересный момент:
& hellip; если в какой-то момент нам потребуется, скажем, распечатать z для пользователя, нам потребуется полностью оценить его & hellip;
Что, естественно, подразумевает, что действительно любое действие IO
, выполняемое из main
, выполняет принудительное вычисление, что должно быть очевидно, если учесть, что программы на Haskell действительно выполняют определенные действия. Все, что должно пройти через последовательность, определенную в main
, должно быть в нормальной форме и поэтому подлежит строгой оценке.
C. А. Макканн понял это правильно в комментариях: единственное, что особенного в main
, это то, что main
определено как особенное; сопоставление с образцом в конструкторе достаточно для обеспечения последовательности, налагаемой монадой IO
. В этом отношении только seq
и сопоставление с образцом являются основополагающими.