考虑一个递归的分支数据结构:
data Tree a = Node (Tree a) (Tree a) | Leaf a
deriving (Show)
可以构造一个具有许多相同分支的Tree
,这似乎可以有效地处理(至少在GHC中) - 例如,通过:
maketree :: Integer -> a -> Tree a
maketree 1 value = Leaf value
maketree depth value = let child = maketree (depth-1) value in Node child child
maketree 32 "Hello"
将返回一个Tree String
概念上包含4294967295个节点 - 但实际上只有32个节点将存储在内存中,而maketree
的主体只会被评估32次。
但是,假设我们实际上尝试以某种方式使用整个树 - 例如,计算节点数:
count :: Tree a -> Integer
count n = case n of
Leaf _ -> 1
Node a b -> 1 + count a + count b
count (maketree 32 "Hello")
将(正确)评估为4294967295,但它会通过评估count
4294967295次的正文来实现。
但是因为实际上只有32个节点对象"存储在内存中,并且由于count
是纯的(作为Haskell函数),因此应该可以为每个节点对象缓存结果,并且仅评估count
32次。
有没有办法让GHC(或任何Haskell实现)这样做?