Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Haskell中避免分配_Haskell_Optimization - Fatal编程技术网

在Haskell中避免分配

在Haskell中避免分配,haskell,optimization,Haskell,Optimization,我正在做一个更复杂的程序,我希望能非常高效,但我现在已经把我的担忧归结为以下简单的程序: main :: IO () main = print $ foldl (+) 0 [(1::Int)..1000000] 我在这里构建并运行它 $ uname -s -r -v -m Linux 3.12.9-x86_64-linode37 #1 SMP Mon Feb 3 10:01:02 EST 2014 x86_64 $ ghc -V The Glorious Glasgow Haskell Com

我正在做一个更复杂的程序,我希望能非常高效,但我现在已经把我的担忧归结为以下简单的程序:

main :: IO ()
main = print $ foldl (+) 0 [(1::Int)..1000000]
我在这里构建并运行它

$ uname -s -r -v -m
Linux 3.12.9-x86_64-linode37 #1 SMP Mon Feb 3 10:01:02 EST 2014 x86_64
$ ghc -V
The Glorious Glasgow Haskell Compilation System, version 7.4.1
$ ghc -O -prof --make B.hs
$ ./B +RTS -P
500000500000
$ less B.prof
        Sun Feb 16 16:37 2014 Time and Allocation Profiling Report  (Final)

           B +RTS -P -RTS

        total time  =        0.04 secs   (38 ticks @ 1000 us, 1 processor)
        total alloc =  80,049,792 bytes  (excludes profiling overheads)

COST CENTRE MODULE  %time %alloc  ticks     bytes

CAF         Main    100.0   99.9     38  80000528


                                                      individual     inherited
COST CENTRE MODULE                  no.     entries  %time %alloc   %time %alloc  ticks     bytes

MAIN        MAIN                     44           0    0.0    0.0   100.0  100.0      0     10872
 CAF        Main                     87           0  100.0   99.9   100.0   99.9     38  80000528
 CAF        GHC.IO.Handle.FD         85           0    0.0    0.0     0.0    0.0      0     34672
 CAF        GHC.Conc.Signal          83           0    0.0    0.0     0.0    0.0      0       672
 CAF        GHC.IO.Encoding          76           0    0.0    0.0     0.0    0.0      0      2800
 CAF        GHC.IO.Encoding.Iconv    60           0    0.0    0.0     0.0    0.0      0       248
看起来每个迭代要分配80个字节。我认为期望编译器在这里生成无分配代码是很合理的


我的期望不合理吗?分配是否是启用分析的副作用?我如何才能找到摆脱分配的方法呢?

在这种情况下,GHC似乎足够聪明,可以将
foldl
优化为更严格的形式,但GHC无法优化掉中间列表,因为
foldl
不是一个,所以这些分配大概是针对
(:)
构造函数的。(EDIT3:不,看起来不是这样;请参阅评论)

通过使用
foldr
fusion,您可以摆脱中间列表:

main :: IO ()
main = print $ foldr (+) 0 [(1::Int)..1000000]
…如您所见:

       k +RTS -P -RTS

    total time  =        0.01 secs   (10 ticks @ 1000 us, 1 processor)
    total alloc =      45,144 bytes  (excludes profiling overheads)
它与我的内存配置文件相同

main = print $ (1784293664 :: Int)
编辑:在这个新版本中,我们用堆分配换取堆栈上的一堆
(1+(2+(3+…))
。要真正获得一个好的循环,我们必须手工编写,如:

main = print $ add 1000000

add :: Int -> Int
add nMax = go 0 1 where
    go !acc !n
        | n == nMax = acc + n
        | otherwise = go (acc+n) (n+1)
显示:

    total time  =        0.00 secs   (0 ticks @ 1000 us, 1 processor)
    total alloc =      45,144 bytes  (excludes profiling overheads)

EDIT2我还没有开始使用Gabriel Gonzalez,但它也可能值得您在应用程序中使用。

使用。在SO和Haskell wiki上,对不同地方的差异进行了很好的讨论。@DanielWagner我用
foldl'
@NovaDenizen得到了完全相同的结果,我希望你用
foldl'
得到同样的结果,因为分析的副作用。您可以尝试正常编译,然后使用
+RTS-s
运行,这将以最小的干扰方式生成非常有用的信息。无论如何对我有用。你在改变你的尺寸吗?我得到
堆栈空间溢出:当前大小为8388608字节。
现在。我可以使用
/B+RTS-K24M-P
来解决这个问题,但是在堆栈上分配24兆对我来说并没有太大的好处。@NovaDenizen它对我来说并没有溢出(在GHC 7.6上;也许默认值更高),但你绝对是对的,我们用堆分配来换取堆栈上的一堆
(1+(2+(3+…)
。对不起,我的帖子在这一点上有误导性;我更新了答案,在GHC7系列中,它变成了自动增长的堆栈,这就是为什么它不再溢出的原因;它看起来像7.8,但不是7.6具有动态增长的堆栈内容。整洁的谢谢@CarlIt,不用手工编写循环,只需使用
foldl'
foldl'
在列表融合的意义上不是一个“好消费者”,但在尾部递归的意义上却是一个好消费者。在这种情况下,没有中间列表。