3

在下面的函数中,我想知道编译器是否足够聪明,x可以计算出保持不变,还是会为列表中的每个项目计算列表的头部?(我正在使用 GHC)

allSame :: Eq a => [a] -> Bool 
allSame xs = all (==x) xs  where x = head xs
4

2 回答 2

11

GHC 中“where”的语义是为“x”分配一个闭包并在所有用途之间共享。将为函数 (== 'x') 生成一个新的闭包,优化器会将其浮出,因此每次遍历只生成一次。

要查看生成的确切代码,请检查核心(例如通过 ghc-core)。GHC 将代码优化为:

M.allSame a eq xs =
    all
      (let 
         ds =
           case xs of 
             []   -> error "bad head"
             x : _-> x
            in
          \y -> x == y
         ) xs

如果性能是一个问题,请考虑使用向量,因为单独的遍历将融合,消除递归。

于 2010-08-27T05:32:06.190 回答
0

我认为 Haskell 只会评估需要什么:所以它正在寻找x并在 - 子句中找到它where。然后我认为它计算x一次并执行all.

如果你想测试它,你可以编写一个myall像 in 一样进行递归的函数all (==x),但本质上只是打印出比较元素。所以你会看到,如果你每次都得到一个新的论点,或者它每次都保持不变。

编辑:

这是一个测试这个的小函数:myall只收集第一个参数并将其放入列表中。

myall x [] = [x]
myall x xs =  x:(myall x (tail xs))

test xs = myall (x) xs where x = head xs

如果您调用test [1,2,3],您将看到结果为[1,1,1,1],即首先x评估为1,然后myall评估。

于 2010-08-27T05:29:08.293 回答