52700.fb2 Учебник по Haskell - читать онлайн бесплатно полную версию книги . Страница 172

Учебник по Haskell - читать онлайн бесплатно полную версию книги . Страница 172

Возвращаясь к исходному примеру, предположим, что арность функции f равна единице. Тогда страте-

гия вставка-вход сначала добавит на стек x и y, а затем будет добирать из стека необходимые аргументы.

Стратегия вычисление-применение сначала вычислит (f x), сохранив y на стеке, затем попробует приме-

нить результат к y. Почему мы говорим попробует? Может так случиться, что арность значения f x окажется

равным трём, но пока у нас есть лишь один аргумент, тогда мы создадим объект PAP, который соответствует

частичному применению.

Эти стратегии применимы как к ленивым, так и к энергичным языкам. Исторически сложилось, что лени-

вые языки тяготеют к первой стратегии, а энергичные ко второй. До недавнего времени и в GHC применялась

первая стратегия. Пока однажды разработчики GHC всё же не решили сравнить две стратегии. Реализовав

обе стратегии, и проверив их на большом количестве разных по сложности программ, они пришли к вы-

воду, что ни одна из стратегий не даёт существенного преимущества на этапе вычислений. Потребление

ресурсов оказалось примерно равным. Но вторая стратегия заметно выигрывала в простоте реализации. По-

дробнее об этом можно почитать в статье Simon Marlow, Simon Peyton Jones: Making a Fast Curry: Push/Enter

vs. Eval/Apply. Описание модели вычислений GHC, которое вы сейчас читаете копирует описание приведён-

ное в этой статье.

Куча

Объекты кучи принято называть замыканиями (closure). Их называют так, потому что обычно для вычис-

ления выражения нам не достаточно знать его текст, например посмотрим на функцию:

mul

= FUN( a ->

let succ = THUNK (add a)

in

foldNat one succ

)

Для того, чтобы вычислить THUNK(add a) нам необходимо знать значение a, это значение определено в те-

ле функции. Оно определяется из контекста. По отношению к объекту такую переменную называют свободной

(free). В куче мы будем хранить не только выражение (add a), но и ссылки на все свободные переменные, ко-

торые участвуют в выражении объекта. Эти ссылки называют довесок (payload). Объект кучи содержит ссылку

на специальную таблицу и довесок. В таблице находятся информация о типе объекта и код, который необ-

ходимо вычислить, а также другая служебная информация. При вычислении объекта мы заменяем ссылки

настоящими значениями или ссылками на конструкторы.

Объект кучи может быть:

FUN – определением функции;

PAP – частичным применением;

CON – полностью применённым конструктором;

THUNK – отложенным вычислением;

BLACKHOLE – это значение используется во время вычисления THUNK. Этот трюк предотвращает появле-

ние утечек памяти.

Мы будем считать, что куча – это таблица, которая ставит в соответствие адресам объекты или вычис-

ленные значения.

Вычисление STG | 159

Стек

Стек служит для быстрого переключения контекста. Мы будем пользоваться стеком при вычислении case-

выражений и THUNK-объектов. При вычислении case-выражения мы сохраняем в стеке альтернативы и место

возврата значения, а сами начинаем вычислять аргумент case-выражения. При вычислении THUNK-объекта

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

При вычислении в стратегии вставка-вход мы будем сохранять в стеке аргументы функции. А при вычис-

лении в стратегии вычисление-применение мы также будем сохранять аргументы функции в стеке. Какая

разница между этими вариантами? В первой стратегии мы можем доставать из стека произвольное число

аргументов, после определения арности функции мы добираем столько, сколько нам нужно, поэтому мы