Было бы абсолютно правильно обернуть каждое значение в thunk.Но поскольку Haskell не является строгим, компиляторы могут выбирать, когда оценивать thunks / expression .В частности, компиляторы могут выбрать оценку выражения раньше, чем это строго необходимо, если это приведет к улучшению кода.
Оптимизация компиляторов Haskell (GHC) выполняет Анализ строгости длявыяснить, какие значения всегда будут вычисляться.
В начале компилятор должен предположить, что ни один из аргументов функции никогда не используется.Затем он перебирает тело функции и пытается найти приложения функций, которые 1) известны строгим (по крайней мере, некоторым из) их аргументов и 2) всегда должны оцениваться для вычисления результата функции.
В вашем примере у нас есть функция (+)
, которая является строгой в обоих своих аргументах.Таким образом, компилятор знает, что и x
, и y
всегда должны оцениваться в этой точке.Так уж получилось, что выражение x+y
всегда необходимо для вычисления результата функции, поэтому компилятор может хранить информацию о строгости функции add
как в x
, так и в y
.
*.1021 * Сгенерированный код для
add
*, таким образом, ожидает целочисленные значения в качестве параметров, а не thunks.Алгоритм становится намного более сложным, когда речь идет о рекурсии (проблема с фиксированной точкой), но основная идея остается той же.
Другой пример:
mkList x y =
if x then y : []
else []
Эта функция займет x
в оценочной форме (в виде логического значения) и y
в виде thunk.Выражение x
должно быть оценено в каждом возможном пути выполнения до mkList
, таким образом, мы можем сделать так, чтобы вызывающая сторона оценила его.Выражение y
, с другой стороны, никогда не используется ни в одном приложении функции, которое является строгим в своих аргументах.Функция cons :
никогда не смотрит на y
, она просто сохраняет ее в списке.Таким образом, y
необходимо передать как thunk, чтобы удовлетворить ленивую семантику Haskell.
mkList False undefined -- absolutely legal
*: add
, конечно, полиморфна и точный тип x
и y
зависит от реализации.