11

我读到这个:

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
4

1 回答 1

13

就一次:

效率:当同一个视图函数应用于函数定义或 case 表达式的多个分支时(例如,在size上面),GHC 会尝试将这些应用程序收集到单个嵌套的 case 表达式中,以便仅应用视图函数一次。GHC 中的模式编译遵循函数式编程语言的实现第 4 章中描述的矩阵算法。当矩阵的第一列的顶部行都是具有“相同”表达式的视图模式时,这些模式将转换为单个嵌套案例。这包括,例如,在一个元组中排列的相邻视图模式,如

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

当前关于两个视图模式表达式何时“相同”的概念非常受限:它甚至不是完全的句法相等。但是,它确实包括变量、文字、应用程序和元组;例如,view ("hi", "there")将收集两个实例。但是,当前的实现无法与 alpha 等效性进行比较,因此(x, view x -> y)不会合并 的两个实例。

GHC 手册

至于您的代码段,问题在于您没有进行优化编译;同时使用ghc -Oand ghc -O2,该行只打印一次。当您在使用 GHC 时遇到与性能相关的问题时,这始终是首先要检查的事情 :)

(顺便说一句,Debug.Trace可以让您检查这些类型的东西,而无需编写手动unsafePerformIOhack。)

于 2012-01-20T20:15:38.347 回答