haskell – 生成不同整数的树会导致空间泄漏

我想生成一个包含不同整数的树并找到它们的总和.这是代码:

{-# LANGUAGE BangPatterns #-}

import Control.Applicative
import Control.Monad.Trans.State

data Tree a = Leaf a | Branch (Tree a) a (Tree a)

new = get <* modify' (+ 1)

tree :: Integer -> Tree Integer
tree n = evalState (go n) 0 where
    go 0 = Leaf <$> new
    go n = Branch <$> go (n - 1) <*> new <*> go (n - 1)

sumTree = go 0 where
    go !a (Leaf n)       = a + n
    go !a (Branch l n r) = go (go (a + n) l) r

main = print $sumTree (tree 20)

用-O2编译它会导致

     348,785,728 bytes allocated in the heap
     147,227,228 bytes copied during GC
      34,656,860 bytes maximum residency (13 sample(s))
          35,468 bytes maximum slop
              72 MB total memory in use (0 MB lost due to fragmentation)

                                     Tot time (elapsed)  Avg pause  Max pause
  Gen  0       565 colls,     0 par    0.764s   1.024s     0.0018s    0.0071s
  Gen  1        13 colls,     0 par    0.936s   1.014s     0.0780s    0.3214s

  INIT    time    0.000s  (  0.001s elapsed)
  MUT     time    0.936s  (  0.764s elapsed)
  GC      time    1.700s  (  2.038s elapsed)
  EXIT    time    0.000s  (  0.002s elapsed)
  Total   time    2.636s  (  2.805s elapsed)

  %GC     time      64.5%  (72.7% elapsed)

  Alloc rate    372,631,936 bytes per MUT second

  Productivity  35.5% of total user, 33.4% of total elapsed

为什么我会漏这个空间?如何删除它?

最佳答案 无论何时构建树,您都应该尝试从上到下独立工作.这通常适用于懒惰,并发,缓存利用率,GC效率等.您构建的树只是按顺序编号的完整二叉树.我建议你考虑使用以下签名并做一些转移:

tree :: Bits b => Int -> Tree b

你可以打破一个起点的辅助函数.

点赞