I\'ve got the following problem: I have a tree of objects of different classes where an action in the child class invalidates the parent. In imperative languages, it is trivial
Here is some zipper code that demonstrates easy modification of the data a cursor points at as well as a "global" property of the tree. We build a tree, move the cursor to the node initially containing a 1, change it to a 3, and are left with a cursor pointing at that node in a fully updated tree.
import Data.Maybe (fromJust)
import Data.Tree
import Data.Tree.Zipper
type NodeData = Either Bool Int
type TreePath a = [TreePos Full a -> TreePos Full a]
firstChild' = fromJust . firstChild
parent' = fromJust . parent
prev' = fromJust . prev
next' = fromJust . next
-- Determine the path from the root of the tree to the cursor.
pathToMe :: TreePos Full NodeData -> TreePath NodeData
pathToMe t | isRoot t = []
| isFirst t = firstChild' : pathToMe (parent' t)
| otherwise = next' : pathToMe (prev' t)
-- Mark a tree as invalid, but leave the cursor in the same place.
invalidate :: TreePos Full NodeData -> TreePos Full NodeData
invalidate t = foldr ($) (setLabel (Left False) (root t)) (pathToMe t)
-- Set a node's internal data.
setData :: Int -> TreePos Full NodeData -> TreePos Full NodeData
setData = (invalidate . ) . setLabel . Right
main = let tree1 = Node (Left True) [Node (Right 1) [], Node (Right 2) []]
Just cursor = firstChild (fromTree tree1)
tree2 = setData 3 cursor
in do putStrLn (drawTree (fmap show tree1))
putStrLn (drawTree (fmap show (toTree tree2)))
putStrLn $ "Cursor at "++show (label tree2)
Output:
Left True
|
+- Right 1
|
`- Right 2
Left False
|
+- Right 3
|
`- Right 2
Cursor at Right 3