一般的なケース:
ツリーへの書き込み方法を知りたい (つまり、最下位レベルの特定のノードを変更し、古いノードを左の子とし、新しいノードを右の子とする別の値を持つノードに置き換える)
より困難にしている特定のアプリケーション:
ファイルから既存のツリーを読み取り、ユーザーにさまざまな質問をし、答えがわからない場合はユーザーに質問する 20 の質問に似たゲームをまとめようとしています。最終的な推測と正しい答え、および正しい答えの間の質問を区別し、新しいエントリをゲームに追加します (推測と答えを指すノードで、推測があった位置を新しい質問に置き換えます)。
質問する
1156 次
1 に答える
4
多くの場合、モナド構造とこの種の木の移植の間には密接な対応があります。これが例です
data Tree a = Leaf a | Branch (Tree a) (Tree a) deriving Functor
instance Monad Tree where
return = Leaf
Leaf a >>= f = f a
Branch l r >>= f = Branch (l >>= f) (r >>= f)
where(>>=)
は、何らかの関数に基づいて葉の拡張 (ツリーの移植) を行っているだけですf :: a -> Tree a
。
その後、お探しの移植を簡単に行うことができます
graftRight :: Eq a => a -> a -> Tree a -> Tree a
graftRight a new t = t >>= go where
go a' | a' == a = Node a new
| otherwise = Leaf a'
しかし、これは非常に非効率的です。なぜなら、Leaf
置換したい特定のものを探してツリー内のすべてを訪問するからです。より多くの情報を知っていれば、より良いことができます。ツリーが何らかの順序で並べ替えられている場合は、fingertree
orを使用splaytree
して効率的な置換を行うことができます。置き換えたいノードがそのパスだけでわかっている場合は、Zipper を使用できます。
data TreeDir = L | R
data ZTree a = Root
| Step TreeDir (Tree a) (ZTree a)
これにより、ツリーのルートに出入りできます
stepIn :: Tree a -> (Tree a, ZTree a)
stepIn t = (t, Root)
stepOut :: (Tree a, ZTree a) -> Maybe (Tree a)
stepOut (t, Root) = Just t
stepOut _ = Nothing
中に入ったら、好きな方向に歩いてください
left :: (Tree a, ZTree a) -> Maybe (Tree a, ZTree a)
left (Leaf a, zip) = Nothing
left (Branch l r, zip) = Just (l, Step R r zip)
right :: (Tree a, ZTree a) -> Maybe (Tree a, ZTree a)
right (Leaf a, zip) = Nothing
right (Branch l r, zip) = Just (r, Step L l zip)
up :: (Tree a, ZTree a) -> Maybe (Tree a, ZTree a)
up (tree, Root) = Nothing
up (tree, Step L l zip) = Just (branch l tree, zip)
up (tree, Step R r zip) = Just (branch tree r, zip)
そして葉を編集する
graft :: (a -> Tree a) -> (Tree a, ZTree a) -> Maybe (Tree a, ZTree a)
graft f (Leaf a, zip) = Just (f a, zip)
graft _ _ = Nothing
または、上からのバインドを使用して、特定の場所の下にあるすべての葉を作成することもできます。
graftAll :: (a -> Tree a) -> (Tree a, ZTree a) -> (Tree a, ZTree a)
graftAll f (tree, zip) = (tree >>= f, zip)
そして、移植を行う前に、ツリーの任意のポイントに移動できます
graftBelow :: (a -> Tree a) -> [TreeDir] -> Tree a -> Maybe (Tree a)
graftBelow f steps t = perform (stepIn t) >>= stepOut where
perform = foldr (>=>) Just (map stepOf steps) -- walk all the way down the path
>=> (Just . graftAll f) -- graft here
>=> foldr (>=>) Just (map (const up) steps) -- walk back up it
stepOf L = left
stepOf R = right
>>> let z = Branch (Branch (Leaf "hello") (Leaf "goodbye"))
(Branch (Branch (Leaf "burrito")
(Leaf "falcon"))
(Branch (Leaf "taco")
(Leaf "pigeon")))
>>> graftBelow Just [] z == z
True
>>> let dup a = Branch (Leaf a) (Leaf a)
>>> graftBelow dup [L, R] z
Just (Branch (Branch (Leaf "hello")
(Branch (Leaf "goodbye")
(Leaf "goodbye")))
(Branch (Branch (Leaf "burrito") (Leaf "falcon"))
(Branch (Leaf "taco") (Leaf "pigeon"))))
>>> graftBelow dup [L, R, R] z
Nothing
一般に、この目標を達成するには多くの方法があります。
于 2013-10-23T21:53:02.190 に答える