私はhaskellのスペースの複雑さについて考える正式な方法を見つけようとしています。私は、グラフ還元(GR)手法についてのこの記事を見つけました。しかし、場合によっては適用に問題があります。次の例を考えてみましょう。
二分木があるとしましょう:
data Tree = Node [Tree] | Leaf [Int]
makeTree :: Int -> Tree
makeTree 0 = Leaf [0..99]
makeTree n = Node [ makeTree (n - 1)
, makeTree (n - 1) ]
ツリーをトラバースする2つの関数。1つ(count1)は適切にストリーミングし、もう1つ(count2)はメモリ内にツリー全体を一度に作成します。プロファイラーによると。
count1 :: Tree -> Int
count1 (Node xs) = 1 + sum (map count1 xs)
count1 (Leaf xs) = length xs
-- The r parameter should point to the root node to act as a retainer.
count2 :: Tree -> Tree -> Int
count2 r (Node xs) = 1 + sum (map (count2 r) xs)
count2 r (Leaf xs) = length xs
count1の場合、それがどのように機能するかを理解していると思います。グラフ還元の観点から、次のようになります。
count1 $ makeTree 2
=> 1 + sum $ map count1 xs
=> 1 + sum $ count1 x1 : map count1 xs
=> 1 + count1 x1 + (sum $ map count1 xs)
=> 1 + (1 + sum $ map count1 x1) + (sum $ map count1 xs)
=> 1 + (1 + sum $ (count1 x11) : map count1 x1) + (sum $ map count1 xs)
=> 1 + (1 + count1 x11 + sum $ map count1 x1) + (sum $ map count1 xs)
=> 1 + (1 + count1 x11 + sum $ map count1 x1) + (sum $ map count1 xs)
=> 1 + (1 + 100 + sum $ map count1 x1) + (sum $ map count1 xs)
=> 1 + (1 + 100 + count x12) + (sum $ map count1 xs)
=> 1 + (1 + 100 + 100) + (sum $ map count1 xs)
=> 202 + (sum $ map count1 xs)
=> ...
シーケンスからは一定の空間で実行されていることは明らかだと思いますが、count2の場合はどうなりますか?
私は他の言語のスマートポインターを理解しているので、 count2関数の余分なrパラメーターがどういうわけかツリーのノードが破壊されるのを防ぐことを漠然と理解していますが、正確なメカニズム、または少なくとも私が使用できる正式なメカニズムを知りたいです他の場合も同様です。
見てくれてありがとう。