Это не совсем так: вы можете оценить термины на Haskell с нетерпением , если докажете, что они не расходятся .
Например, когда вы видите f x
, вы можете сначала выполнить до 1000 шагов x (остановка при достижении WHNF (нормальная форма слабой головы) или ошибка), а затем передать его на f - семантика сохраняется, но если вы думаете, что x будет оцениваться, то вы можете организовать это заранее как оптимизацию.
Если x = fix id
, он просто сдастся после 1000 шагов и никуда не денется. Если x = undefined
, это вызовет ошибку и сдастся (восстанавливая исходный блок и передавая его f ). И так далее.
Если x = [1..]
, то это может привести к уменьшению его до 1 : 2 : 3 : ... : 999 : 1000 : [1001..]
, достижению предела и остановке на нем, передавая результат в f .
В основном: либо доказывая, что выражение не может расходиться, либо ограничивая оценку так, чтобы все заканчивалось, даже если оно и происходит. Без изменений в семантике и, возможно, значительное улучшение производительности.
Конечно, недостатком является то, что если x окажется действительно дорогим вычислением, для которого f использует только половину, вы потратите 1000 шагов сокращения, тратя время впустую. А в случае [1..]
вы можете использовать много памяти для хранения списка; если f обрабатывает список по одному элементу за раз, каждый раз отбрасывая голову, тогда вы тратите впустую память. Вот почему это сложно:)
Страница, на которую вы изначально ссылались, более детально описывает используемые методы.