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

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

чение f ещё не вычислено. Оно является T HUNK. Тогда мы сохраним аргументы на стеке и вычислим его.

В следующем правиле мы раскрываем частичное применение. Мы просто организуем вызов функции со все-

ми аргументами (и со стека и из частичного применения). Последнее правило срабатывает после третьего.

Когда мы вычислим T HUNK и увидим там F UN или P AP . Тогда мы составляем применение функции.

Сложность применения стратегии вставка-вход связана с плохо предсказуемым изменением стека. Если в

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

добавляем их по одному и неизвестно сколько снимем в следующий раз. Кроме того стратегия вычисление-

применение позволяет проводить оптимизацию перемещения аргументов. Вместо стека мы можем хранить

аргументы в регистрах. Тогда скорость обращения к аргументам резко возрастёт.

10.4 Представление значений в памяти. Оценка занимаемой памяти

Ранее мы говорили, что полностью вычисленное значение – это дерево, в узлах которого находятся одни

лишь конструкторы. Процесс вычисления похож на очистку дерева выражения от синонимов. Мы начинаем с

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

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

на объекты в куче. Ссылки – это атомарные переменные. Полностью вычисленное значение является сетью

(или графом) объектов кучи типа CON.

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

пьютера состоит из ячеек, в которых хранятся значения. У каждой ячейки есть адрес. Ячейки памяти неде-

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

Каждый конструктор требует столько слов сколько у него полей плюс ещё одно слово для ссылки на

служебную информацию (она нужна вычислителю). Посмотрим на примеры:

data Int = I# Int#

-- 2 слова

data Pair a b = Pair a b

-- 3 слова

У этого правила есть исключение. Если у конструктора нет полей, то есть он является константой или

примитивным конструктором, то в процессе вычисления значение этого конструктора представлено ссылкой.

Это означает, что внутри программы все значения ссылаются на одну область памяти. У нас действительно

есть лишь один пустой список или одно значение True или False.

Посчитаем число слов в значении [Pair 1 2]. Для этого для начала перепишем его в STG

nil = []

-- глобальный объект (не в счёт)

162 | Глава 10: Реализация Haskell в GHC

let x1

= I# 1

-- 2 слова

x2

= I# 2

-- 2 слова

p

= Pair x1 x2

-- 3 слова

val = Cons p nil

-- 3 слова

in

val

------------

-- 10 слов

Поскольку объект кучи CON может хранить только ссылки, нам пришлось введением дополнительных

переменных “развернуть” значение. Примитивный конструктор не считается, поскольку он сохранён гло-