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

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

...

$ ./Rules

Cons 101 (Cons 102 (Cons 103 Nil))

Среди прочих правил, определённых в стандартных библиотеках, сработало и наше. Составим правила,

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

применение mapL на один mapL c композицией функций, также промежуточный список будет устранён в

связке foldrL/mapL.

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

Прагма UNPACK

Наш основной враг на этапе оптимизации программы это лишние объекты кучи. Чем меньше объектов

мы создаём на пути к результату, тем эффективнее наша программа. С помощью прагмы INLINE мы можем

избавиться от многих объектов, связанных с вызовом функции, это объекты типа FUN. Прагма UNPACK позволя-

ет нам бороться с лишними объектами типа CON. В прошлой главе мы говорили о том, что значения в Haskell

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

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

определённым значением (undefined). Такие значения называются запакованными (boxed). Незапакованное

значение, это примитивное значение, как оно представлено в памяти компьютера. Вспомним определение

целых чисел:

data Int = I# Int#

По традиции все незапакованные значения пишутся с решёткой на конце. Запакованные значения позво-

ляют отклдывать вычисления, пользоваться undefined при определении функции. Но за эту гибкость прихо-

дится платить. Вспомним расход памяти в выражении [Pair 1 2]

nil = []

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

let x1

= I# 1

-- 2 слова

x2

= I# 2

-- 2 слова

p

= Pair x1 x2

-- 3 слова

val = Cons p nil

-- 3 слова

in

val

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

-- 10 слов

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

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

нагрузка составляет 2 N. С помощью прагмы UNPACK мы можем отказаться от ленивой гибкости в пользу

меньшего расхода памяти. Эта прагма позволяет встраивать

один конструктор в поле другого. Это поле должно быть строгим (с пометкой ! ) и мономорфным (тип поля

должен быть конкретным типом, а не параметром), причём подчинённый тип должен содержать лишь один

конструктор (у него нет альтернатив):

data PairInt = PairInt

{-# UNPACK #-} !Int

{-# UNPACK #-} !Int

Мы конкретизировали поля Pair и сделали их строгими с помощью восклицательных знаков. После этого