透镜和拉链的遍历树

我正在学习镜头套件。 我必须说这是一项颇具挑战性的任务。

有人可以告诉我如何从镜头穿过拉链树吗? 特别是,我该如何编写一个函数,该函数需要一个根的列表并允许我访问子树的分支?

假设我有这棵树。 如果我的输入是[1, 3] ,该函数应该允许我访问节点10和11。

import Control.Lens
import Data.Tree
import Data.Tree.Lens

testTree = Node 1 [ Node 2 [ Node 4 [ Node 6 [], Node 8 [] ],
                             Node 5 [ Node 7 [], Node 9 [] ] ],
                    Node 3 [ Node 10 [], 
                             Node 11 [] ] 
                  ]

zipperTree = zipper testTree

另外,我如何使用saveTaperestoreTape来保存遍历路径(到StateT或IORef)?


编辑:我通常在ghci中试验以理解新代码,所以对于像我这样的人,我已经创建了一个Haskell学校/ post页面,它附带下面的例子,但它们是可编辑和可运行的。


想想这个例子会回答你的问题,但为了方便,我将修改一个不同的节点。 我对镜头拉链功能的了解很浅。 与许多其他软件包相比,读取和习惯镜头包装中的类型需要更长的时间,但之后并不差。 在本文之前,我没有使用镜头包装中的拉链模块或树形模块。

树不漂亮,漂亮,很好地show ,所以如果我有时间我会回来,并添加了一些漂亮的打印出来放在否则它可能是关键在这些例子中,REPL工作,看看发生了什么。

查看

如果我想查看第一个节点的值,根据树形镜头包将其称为根,那么您可以:

zipperTree & downward root & view focus

修改

修改该值并重新创建树(重新解压缩树):

zipperTree & downward root & focus .~ 10 & rezip

如果你想移动分支,那么你需要使用downward branches 。 这里是一个例子,它修改了第一个分支的根目录,并重新编译树:

zipperTree & downward branches 
           & fromWithin traverse 
           & downward root 
           & focus .~ 5 
           & rezip

在这里,我向下移动到分支列表。 然后我用fromWithin使用使用traverse遍历列表,如果这是一个元组,我可以用both来代替。

保存并重放遍历路径

saveTaperestoreTape允许您将您的位置保存在拉链中,以便后者可以恢复。

保存位置:

tape = zipperTree & downward branches 
                  & fromWithin traverse 
                  & downward root 
                  & saveTape

然后重新穿过树来遍历我可以:

t <- (restoreTape tape testTree)

然后你可以使用t作为新的拉链,并按照正常的方式修改它:

t & focus .~ 15 & rezip

磁带重放您采取的步骤,因此可以在其他树上工作,以便遵循上述定义的磁带。

testTree2 = Node 1 [ Node 2 [] ]
t2 <- (restoreTape tape testTree2)
t2 & focus .~ 25 & rezip

修改多个位置

如果你想修改多个根,只需重新拉链拉链即可。 以下修改testTree2的两个根:

zipper testTree2 & downward root 
                 & focus .~ 11 
                 & upward 
                 & downward branches 
                 & fromWithin traverse 
                 & downward root 
                 & focus .~ 111 
                 & rezip

根据我的经验,你通常不需要拉链 。 在这种情况下,您可以定义一个遍历 ,这将允许您在给定根节点路径的情况下访问子树。

-- Make things a little easier to read
leaf :: a -> Tree a
leaf = return

testForest :: Forest Int
testForest = [ Node 1 [ Node 2 [ Node 4 [ leaf 6, leaf 8]
                               , Node 5 [ leaf 7, leaf 9]]
                      , Node 3 [ leaf 10, leaf 11]]]

-- | Handy version of foldr with arguments flipped
foldEndo :: (a -> b -> b) -> [a] -> b -> b
foldEndo f xs z = foldr f z xs

-- | Traverse the subforests under a given path specified by the values of
-- the parent nodes.
path :: Eq a => [a] -> Traversal' (Forest a) (Forest a)
path = foldEndo $ k ->     -- for each key in the list
       traverse               -- traverse each tree in the forest
     . filtered (hasRoot k)   -- traverse a tree when the root matches
     . branches               -- traverse the subforest of the tree

  where
  hasRoot :: Eq a => a -> Tree a -> Bool
  hasRoot k t = k == view root t

-- | Helper function for looking at 'Forest's.
look :: Show a => Forest a -> IO ()
look = putStr . drawForest . (fmap . fmap) show

-- Just show 'path' in action

demo1 = look $ testForest & path [1,3] .~ []
demo2 = look $ testForest & path [1,3] . traverse . root *~ 2
demo3 = look $ testForest ^. path [1,3]
demo4 = [] == testForest ^. path [9,3]
demo5 = traverseOf_ (path [1,3]) print testForest
链接地址: http://www.djcxy.com/p/58759.html

上一篇: traversal tree with Lens and Zippers

下一篇: Maintaining complex state in Haskell