Читаем Учебник по Haskell полностью

на функции определяется числом узлов в синтаксическом дереве кода её правой части. Директивой INLINE

мы приказываем GHC встроить функцию. Также есть более слабая версия этой прагмы –INELINABLE. Этой

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

Задать порог величины функции для встраивания можно с помощью флага -funfolding-use-

threshold=16. Отметим, что если функция не является экспортируемой и используется лишь один раз,

то GHC втроит её в любом случае, поэтому стоит определять списки экспортируемых определений в шапке

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

Прагма INLINE может стоять в любом месте, где можно было бы объявить тип значения. Так например

можно указать компилятору встраивать методы класса:

Оптимизация программ | 173

instance Monad T where

{-# INLINE return #-}

return = ...

{-# INLINE (>>=) #-}

(>>=)

= ...

Встраивание значений может существенно ускорить программу. Но не стоит венчать каждую экспортиру-

емую функцию прагмой INLINE, возможно GHC встроит их автоматически. Посмотреть какие функции были

встроены можно по определениям, попавшим в файл . hi.

Например если мы скомпилируем такой код с флагом ddump-hi:

module Inline(f, g) where

g :: Int -> Int

g x = x + 2

f :: Int -> Int

f x = g $ g x

то среди прочих определений увидим:

ghc -c -ddump-hi -O Inline. hs

...

f :: GHC.Types.Int -> GHC.Types.Int

{- Arity: 1, HasNoCafRefs, Strictness: U(L)m,

Unfolding: InlineRule (1, True, False)

(\ x :: GHC.Types.Int ->

case x of wild { GHC.Types.I# x1 ->

GHC.Types.I# (GHC.Prim.+# (GHC.Prim.+# x1 2) 2) }) -}

...

В этом виде прочесть функцию не так просто. Ко всем именам добавлены имена модулей. Приведём

вывод к более простому виду с помощью флага dsuppress-all:

ghc -c -ddump-hi -dsuppress-all -O Inline. hs

...

f :: Int -> Int

{- Arity: 1, HasNoCafRefs, Strictness: U(L)m,

Unfolding: InlineRule (1, True, False)

(\ x :: Int -> case x of wild { I# x1 -> I# (+# (+# x1 2) 2) }) -}

...

Мы видим, что все вызовы функции g были заменены. Если вы всё же подозреваете, что GHC не справ-

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

INLINE, но при этом лучше узнать, привело ли это к росту производительности, проверить с помощью про-

филирования.

Отметим также прагму NOINLINE с её помощью мы можем запретить встраивание функции. Эта праг-

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

неконтролируемые побочные эффекты, может повлиять на её результат.

Прагма RULES

Разработчики GHC хотели, чтобы их компилятор был расширяемым и программист мог бы определять

специфические для его приложения правила оптимизации. Для этого была придумана прагма RULES. За счёт

чистоты функций мы можем в очень простом виде выражать инварианты программы. Инвариант – это неко-

торое свойство значения, которое остаётся постоянным при некоторых преобразованиях. Наиболее распро-

странённые инварианты имеют собственные имена. Например, это коммутативность сложения:

forall a b. a + b = b + a

Здесь мы пишем: для любых a и b изменение порядка следования аргументов у (+) не влияет на результат.

С ключевым словом forall мы уже когда-то встречались, когда говорили о типе ST. Помните тип функции

runST? Пример свойства функции map:

forall f g.

map f . map g = map (f . g)

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

Это свойство принято называть дистрибутивностью. Мы видим, что функция композиции дистрибутив-

на относительно функции map. Инварианты определяют скрытые закономерности значений. За счёт чистоты

функций мы можем безболезненно заменить в любом месте программы левую часть на правую или наобо-

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

эффективнее другой. Так в примере с map выражение справа от знака равно гораздо эффективнее, поскольку

в нём мы не строим промежуточный список. Особенно ярко разница проявляется в энергичной стратегии

вычислений. Или посмотрим на такое совсем простое свойство:

map id = id

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

списка. Вряд ли программист станет писать такие выражения, однако они могут появиться после выполнения

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

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

map f []

= []

map f (x:xs)

= f x : map f xs

map id a

= a

map f (map g x) = map (f . g) x

Словно теперь мы можем проводить сопоставление с образцом не только по конструкторам, но и по выра-

жениям самого языка и функция map стала конструктором. Что интересно, зависимости могут быть какими

угодно, они могут выражать закономерности, присущие той области, которую мы описываем. В дополни-

Перейти на страницу:

Похожие книги

1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

Книга содержит полное описание приемов и методов работы с программой 1С:Бухгалтерия 8. Рассматривается автоматизация всех основных участков бухгалтерии: учет наличных и безналичных денежных средств, основных средств и НМА, прихода и расхода товарно-материальных ценностей, зарплаты, производства. Описано, как вводить исходные данные, заполнять справочники и каталоги, работать с первичными документами, проводить их по учету, формировать разнообразные отчеты, выводить данные на печать, настраивать программу и использовать ее сервисные функции. Каждый урок содержит подробное описание рассматриваемой темы с детальным разбором и иллюстрированием всех этапов.Для широкого круга пользователей.

Алексей Анатольевич Гладкий

Программирование, программы, базы данных / Программное обеспечение / Бухучет и аудит / Финансы и бизнес / Книги по IT / Словари и Энциклопедии
1С: Управление торговлей 8.2
1С: Управление торговлей 8.2

Современные торговые предприятия предлагают своим клиентам широчайший ассортимент товаров, который исчисляется тысячами и десятками тысяч наименований. Причем многие позиции могут реализовываться на разных условиях: предоплата, отсрочка платежи, скидка, наценка, объем партии, и т.д. Клиенты зачастую делятся на категории – VIP-клиент, обычный клиент, постоянный клиент, мелкооптовый клиент, и т.д. Товарные позиции могут комплектоваться и разукомплектовываться, многие товары подлежат обязательной сертификации и гигиеническим исследованиям, некондиционные позиции необходимо списывать, на складах периодически должна проводиться инвентаризация, каждая компания должна иметь свою маркетинговую политику и т.д., вообщем – современное торговое предприятие представляет живой организм, находящийся в постоянном движении.Очевидно, что вся эта кипучая деятельность требует автоматизации. Для решения этой задачи существуют специальные программные средства, и в этой книге мы познакомим вам с самым популярным продуктом, предназначенным для автоматизации деятельности торгового предприятия – «1С Управление торговлей», которое реализовано на новейшей технологической платформе версии 1С 8.2.

Алексей Анатольевич Гладкий

Финансы / Программирование, программы, базы данных