Haskell编译器如何处理'where'语句?

时间:2010-08-27 04:45:11

标签: compiler-construction haskell ghc

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

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

2 个答案:

答案 0 :(得分:11)

GHC中'where'的语义是单个闭包将被分配给'x'并在所有用途中共享。将生成一个用于函数(=='x')的新闭包,优化器将浮出它,这样它每次遍历只生成一次。

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

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

如果需要考虑性能,请考虑使用向量,因为单独的遍历将融合,从而消除递归。

答案 1 :(得分:0)

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

如果你想测试它,你可以编写一个函数myall来执行像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