ViewPatterns и несколько вызовов в Haskell

Я читал это:

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?

ИЗМЕНИТЬ:

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

{-# 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

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

Эффективность: когда одна и та же функция просмотра применяется в множественные ветки определения функции или выражение case (например, в size выше), GHC пытается собрать эти приложений в одно вложенное выражение case, так что представление функция применяется только один раз. Сбор образцов в 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 хаки.)