【发布时间】:2011-09-06 16:07:18
【问题描述】:
假设有人编写了一个程序来下棋或解数独。在这种程序中,有一个表示游戏状态的树结构是有意义的。
这棵树会很大,“几乎是无限的”。这本身不是问题,因为 Haskell 支持无限数据结构。
一个熟悉的无限数据结构示例:
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
节点仅在第一次使用时才分配,因此列表占用有限的内存。如果他们不保留对其头部的引用,也可以迭代无限列表,从而允许垃圾收集器收集不再需要的部分。
回到树的例子——假设对树进行了一些迭代,如果树的根仍然需要,则迭代的树节点可能不会被释放(例如在迭代深化搜索中,树将被迭代多次,因此需要保留根)。
我想到的一个可能的解决方案是使用“unmemo-monad”。
我将尝试使用 monadic 列表来演示这个 monad 应该做什么:
import Control.Monad.ListT (ListT) -- cabal install List
import Data.Copointed -- cabal install pointed
import Data.List.Class
import Prelude hiding (enumFromTo)
nums :: ListT Unmemo Int -- What is Unmemo?
nums = enumFromTo 0 1000000
main = print $ div (copoint (foldlL (+) 0 nums)) (copoint (lengthL nums))
使用nums :: [Int],程序将占用大量内存,因为lengthL nums 在迭代foldlL (+) 0 nums 时需要对nums 的引用。
Unmemo 的目的是让运行时不让节点不断迭代。
我尝试将((->) ()) 用作Unmemo,但它产生的结果与nums :: [Int] 的结果相同——程序使用了大量内存,通过+RTS -s 运行它就可以看出。
有没有实现我想要的Unmemo?
【问题讨论】:
-
这对我来说似乎不是一个单子的工作。我不认为空间泄漏是由您认为的原因造成的。
-
@Dan:如果我只留下
foldlL或lengthL之一,那么就没有空间泄漏。这让我认为问题在于 GHC 没有收集空间。您认为导致泄漏的原因是什么? -
你确定这不是完全惰性“优化”的问题吗?参见例如comments.gmane.org/gmane.comp.lang.haskell.cafe/103616
-
有一种方法可以使用 Joachim Breitner 的 hackage.haskell.org/package/ghc-dup(这只是一个概念证明)。我有一篇博文haskellexists.blogspot.de/2016/01/… 详细说明。
标签: performance haskell