ViewPatterns и множественные звонки в Haskell - PullRequest
11 голосов
/ 21 января 2012

Я прочитал это:

http://hackage.haskell.org/trac/ghc/wiki/ViewPatterns

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

Итак, допустим, у нас есть:

{-# LANGUAGE ViewPatterns #-}
...

f (view -> Nothing) = ...
f (view -> Just x) = ...

view :: a -> Maybe b

Теперь, скажем, я вызываюf a.view вызывается дважды или только один раз для данного аргумента a?

EDIT :

Я попытался выяснить, так ли это, и написалследующее:

{-# LANGUAGE ViewPatterns #-}

import System.IO.Unsafe

blah (ble -> Nothing) = 123
blah (ble -> Just x) = x

ble x = unsafePerformIO $ do
    putStrLn $ "Inside ble: " ++ show x
    return x

main :: IO ()
main = do
    putStrLn $ "Main: " ++ show (blah $ Just 234)

Вывод с использованием GHC:

Inside ble: Just 234
Inside ble: Just 234
Main: 234

Вывод с использованием GHC (с оптимизацией)

Inside ble: Just 234
Main: 234

Вывод с использованием GHCi:

Main: Inside ble: Just 234
Inside ble: Just 234
234

1 Ответ

13 голосов
/ 21 января 2012

Только один раз:

Эффективность: когда та же функция просмотра применяется в несколько ветвей определения функции или выражения регистра (например, в size выше), GHC пытается собрать эти приложения в одном выражении вложенного регистра, так что представление Функция применяется только один раз. Компиляция шаблона в GHC следует матричный алгоритм описан в главе 4 Реализация языков функционального программирования . Когда все верхние строки первого столбца матрицы - это шаблоны вида с «одно и то же» выражение, эти шаблоны превращаются в одно вложенное дело. Это включает, например, соседние шаблоны вида, которые выстраиваются в кортеже, как в

f ((view -> A, p1), p2) = e1
f ((view -> B, p3), p4) = e2

Текущее представление о том, когда два выражения шаблона представления являются То же самое "очень ограничено: это даже не полное синтаксическое равенство. Тем не менее, он включает в себя переменные, литералы, приложения и кортежи; например, два экземпляра view ("hi", "there") будут собраны. Однако текущая реализация не сравнивается до альфа-эквивалентность, поэтому два экземпляра (x, view x -> y) не будут объединены.

- Руководство GHC

Что касается вашего фрагмента, проблема в том, что вы не компилируете с оптимизацией; как ghc -O, так и ghc -O2, строка печатается только один раз. Это всегда первое, что нужно проверять, когда у вас возникают проблемы с производительностью при использовании GHC:)

(Кстати, Debug.Trace позволяет проверять подобные вещи без необходимости писать ручные unsafePerformIO хаки.)

...