module Data.Tree.Zipper
( TreeLoc(..)
, fromTree
, fromForest
, toForest
, toTree
, parent
, root
, getChild
, findChild
, firstChild
, lastChild
, left
, right
, isRoot
, isFirst
, isLast
, isLeaf
, isChild
, hasChildren
, insertLeft
, insertRight
, insertDownFirst
, insertDownLast
, insertDownAt
, delete
, setTree
, modifyTree
, modifyLabel
, setLabel
, getLabel
) where
import Data.Tree
data TreeLoc a = Loc
{ tree :: Tree a
, lefts :: Forest a
, rights :: Forest a
, parents :: [(Forest a, a, Forest a)]
} deriving (Read,Show,Eq)
parent :: TreeLoc a -> Maybe (TreeLoc a)
parent loc =
case parents loc of
(pls,v,prs) : ps -> Just
Loc { tree = Node v (combChildren (lefts loc) (tree loc) (rights loc))
, lefts = pls, rights = prs, parents = ps
}
[] -> Nothing
root :: TreeLoc a -> TreeLoc a
root loc = maybe loc root (parent loc)
left :: TreeLoc a -> Maybe (TreeLoc a)
left loc =
case lefts loc of
t : ts -> Just loc { tree = t, lefts = ts, rights = tree loc : rights loc }
[] -> Nothing
right :: TreeLoc a -> Maybe (TreeLoc a)
right loc =
case rights loc of
t : ts -> Just loc { tree = t, lefts = tree loc : lefts loc, rights = ts }
[] -> Nothing
firstChild :: TreeLoc a -> Maybe (TreeLoc a)
firstChild loc =
case subForest (tree loc) of
t : ts -> Just
Loc { tree = t, lefts = [], rights = ts , parents = downParents loc }
[] -> Nothing
lastChild :: TreeLoc a -> Maybe (TreeLoc a)
lastChild loc =
case reverse (subForest (tree loc)) of
t : ts -> Just
Loc { tree = t, lefts = ts, rights = [], parents = downParents loc }
[] -> Nothing
getChild :: Int -> TreeLoc a -> Maybe (TreeLoc a)
getChild n loc =
do (t:ls,rs) <- splitChildren [] (subForest (tree loc)) n
return Loc { tree = t, lefts = ls, rights = rs, parents = downParents loc }
findChild :: (Tree a -> Bool) -> TreeLoc a -> Maybe (TreeLoc a)
findChild p loc =
do (ls,t,rs) <- split [] (subForest (tree loc))
return Loc { tree = t, lefts = ls, rights = rs, parents = downParents loc }
where split acc (x:xs) | p x = Just (acc,x,xs)
split acc (x:xs) = split (x:acc) xs
split _ [] = Nothing
downParents :: TreeLoc a -> [(Forest a, a, Forest a)]
downParents loc = (lefts loc, rootLabel (tree loc), rights loc) : parents loc
fromTree :: Tree a -> TreeLoc a
fromTree t = Loc { tree = t, lefts = [], rights = [], parents = [] }
fromForest :: Forest a -> Maybe (TreeLoc a)
fromForest (t:ts) = Just Loc { tree = t, lefts = [], rights = ts, parents = [] }
fromForest [] = Nothing
toTree :: TreeLoc a -> Tree a
toTree loc = tree (root loc)
toForest :: TreeLoc a -> Forest a
toForest loc = let r = root loc in combChildren (lefts r) (tree r) (rights r)
isRoot :: TreeLoc a -> Bool
isRoot loc = null (parents loc)
isFirst :: TreeLoc a -> Bool
isFirst loc = null (lefts loc)
isLast :: TreeLoc a -> Bool
isLast loc = null (rights loc)
isLeaf :: TreeLoc a -> Bool
isLeaf loc = null (subForest (tree loc))
isChild :: TreeLoc a -> Bool
isChild loc = not (isRoot loc)
hasChildren :: TreeLoc a -> Bool
hasChildren loc = not (isLeaf loc)
setTree :: Tree a -> TreeLoc a -> TreeLoc a
setTree t loc = loc { tree = t }
modifyTree :: (Tree a -> Tree a) -> TreeLoc a -> TreeLoc a
modifyTree f loc = setTree (f (tree loc)) loc
modifyLabel :: (a -> a) -> TreeLoc a -> TreeLoc a
modifyLabel f loc = setLabel (f (getLabel loc)) loc
setLabel :: a -> TreeLoc a -> TreeLoc a
setLabel v loc = modifyTree (\t -> t { rootLabel = v }) loc
getLabel :: TreeLoc a -> a
getLabel loc = rootLabel (tree loc)
insertLeft :: Tree a -> TreeLoc a -> TreeLoc a
insertLeft t loc = loc { tree = t, rights = tree loc : rights loc }
insertRight :: Tree a -> TreeLoc a -> TreeLoc a
insertRight t loc = loc { tree = t, lefts = tree loc : lefts loc }
insertDownFirst :: Tree a -> TreeLoc a -> TreeLoc a
insertDownFirst t loc =
loc { tree = t, lefts = [], rights = subForest (tree loc)
, parents = downParents loc }
insertDownLast :: Tree a -> TreeLoc a -> TreeLoc a
insertDownLast t loc =
loc { tree = t, lefts = reverse (subForest (tree loc)), rights = []
, parents = downParents loc }
insertDownAt :: Int -> Tree a -> TreeLoc a -> Maybe (TreeLoc a)
insertDownAt n t loc =
do (ls,rs) <- splitChildren [] (subForest (tree loc)) n
return loc { tree = t, lefts = ls, rights = rs, parents = downParents loc }
delete :: TreeLoc a -> Maybe (TreeLoc a)
delete loc =
case rights loc of
t : ts -> Just loc { tree = t, rights = ts }
_ -> case lefts loc of
t : ts -> Just loc { tree = t, lefts = ts }
_ -> do loc1 <- parent loc
return $ modifyTree (\t -> t { subForest = [] }) loc1
splitChildren :: [a] -> [a] -> Int -> Maybe ([a],[a])
splitChildren acc xs 0 = Just (acc,xs)
splitChildren acc (x:xs) n = splitChildren (x:acc) xs $! n1
splitChildren _ _ _ = Nothing
combChildren ls t rs = foldl (flip (:)) (t:rs) ls