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

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

deriving (Show)

foldrL :: (a -> b -> b) -> b -> List a -> b

foldrL cons nil x = case x of

Nil

-> nil

Cons a as

-> cons a (foldrL cons nil as)

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

mapL :: (a -> b) -> List a -> List b

mapL = undefined

{-# RULES

”mapL”

forall f xs.

mapL f xs = foldrL (Cons . f) Nil xs

#-}

main = print $ mapL (+100) $ Cons 1 $ Cons 2 $ Cons 3 Nil

Функция mapL не определена, вместо этого мы сделали косвенное определение в прагме RULES. Проверим,

для того чтобы RULES заработали, необходимо компилировать с одним из флагов оптимизаций O или O2:

$ ghc --make -O Rules.hs

$ ./Rules

Rules: Prelude.undefined

Что-то не так. Дело в том, что GHC слишком поторопился и заменил простую функцию mapL на её опре-

деление. Функция $ также очень короткая, если бы нам удалось задержать встраивание mapL, тогда $ превра-

тилось бы в обычное применение и наши правила сработали бы.

Фазы компиляции

Для решения этой проблемы в прагмы RULES и INLINE были введены ссылки на фазы компиляции. С по-

мощью них мы можем указать GHC в каком порядке реагировать на эти прагмы. Фазы пишутся в квадратных

скобках:

{-# INLINE [2] someFun #-}

{-# RULES

”fun” [0] forall ...

”fun” [1] forall ...

”fun” [~1] forall ...

#-}

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

трёх, до нуля. Мы можем сослаться на фазу двумя способами: просто номером и номером с тильдой. Ссылка

без тильды говорит: попытайся применить это правило как можно раньше до тех пор пока не наступит данная

фаза, далее не применяй. Ссылка с тильдой говорит: подожди до наступления этой фазы. В нашем примере

мы задержим встраивание для mapL и foldrL так:

{-# INLINE [1] foldrL #-}

foldrL :: (a -> b -> b) -> b -> List a -> b

{-# INLINE [1] mapL #-}

mapL :: (a -> b) -> List a -> List b

Посмотреть какие правила сработали можно с помощью флага ddump-rule-firings. Теперь скомпилиру-

ем:

$ ghc --make -O Rules.hs -ddump-rule-firings

...

Rule fired: SPEC Main.$fShowList [GHC.Integer.Type.Integer]

Rule fired: mapL

Rule fired: Class op show