module Data.Tree.Zipper
( TreePos
, PosType, Empty, Full
, before, after, forest, tree, label, parents
, fromTree
, fromForest
, toForest
, toTree
, parent
, root
, prevSpace, prevTree, prev, first, spaceAt
, nextSpace, nextTree, next, last
, children, firstChild, lastChild, childAt
, isRoot
, isFirst
, isLast
, isLeaf
, isContained
, hasChildren
, insert
, delete
, setTree
, modifyTree
, modifyLabel
, setLabel
) where
import Data.Tree
import Prelude hiding (last)
data TreePos t a = Loc
{ _content :: t a
, _before :: Forest a
, _after :: Forest a
, _parents :: [(Forest a, a, Forest a)]
} deriving (Read,Show,Eq)
before :: PosType t => TreePos t a -> Forest a
before = _before
after :: PosType t => TreePos t a -> Forest a
after = _after
parents :: PosType t => TreePos t a -> [(Forest a, a, Forest a)]
parents = _parents
data Empty a = E deriving (Read,Show,Eq)
newtype Full a = F { unF :: Tree a } deriving (Read,Show,Eq)
class PosType t where
_prev :: TreePos t a -> Maybe (TreePos t a)
_next :: TreePos t a -> Maybe (TreePos t a)
_forest :: TreePos t a -> Forest a
instance PosType Full where
_prev = prevTree . prevSpace
_next = nextTree . nextSpace
_forest loc = foldl (flip (:)) (tree loc : after loc) (before loc)
instance PosType Empty where
_prev = fmap prevSpace . prevTree
_next = fmap nextSpace . nextTree
_forest loc = foldl (flip (:)) (after loc) (before loc)
prev :: PosType t => TreePos t a -> Maybe (TreePos t a)
prev = _prev
next :: PosType t => TreePos t a -> Maybe (TreePos t a)
next = _next
forest :: PosType t => TreePos t a -> Forest a
forest = _forest
parent :: PosType t => TreePos t a -> Maybe (TreePos Full a)
parent loc =
case parents loc of
(ls,a,rs) : ps -> Just
Loc { _content = F (Node a (forest loc))
, _before = ls
, _after = rs
, _parents = ps
}
[] -> Nothing
root :: TreePos Full a -> TreePos Full a
root loc = maybe loc root (parent loc)
prevSpace :: TreePos Full a -> TreePos Empty a
prevSpace loc = loc { _content = E, _after = tree loc : after loc }
prevTree :: TreePos Empty a -> Maybe (TreePos Full a)
prevTree loc =
case before loc of
t : ts -> Just loc { _content = F t, _before = ts }
[] -> Nothing
nextSpace :: TreePos Full a -> TreePos Empty a
nextSpace loc = loc { _content = E, _before = tree loc : before loc }
nextTree :: TreePos Empty a -> Maybe (TreePos Full a)
nextTree loc =
case after loc of
t : ts -> Just loc { _content = F t, _after = ts }
[] -> Nothing
children :: TreePos Full a -> TreePos Empty a
children loc =
Loc { _content = E
, _before = []
, _after = subForest (tree loc)
, _parents = (before loc, rootLabel (tree loc), after loc)
: parents loc
}
first :: TreePos Empty a -> TreePos Empty a
first loc = loc { _content = E
, _before = []
, _after = reverse (before loc) ++ after loc
}
last :: TreePos Empty a -> TreePos Empty a
last loc = loc { _content = E
, _before = reverse (after loc) ++ before loc
, _after = []
}
spaceAt :: Int -> TreePos Empty a -> TreePos Empty a
spaceAt n loc = loc { _content = E
, _before = reverse as
, _after = bs
}
where (as,bs) = splitAt n (forest loc)
firstChild :: TreePos Full a -> Maybe (TreePos Full a)
firstChild = nextTree . children
lastChild :: TreePos Full a -> Maybe (TreePos Full a)
lastChild = prevTree . last . children
childAt :: Int -> TreePos Full a -> Maybe (TreePos Full a)
childAt n | n < 0 = const Nothing
childAt n = nextTree . spaceAt n . children
fromTree :: Tree a -> TreePos Full a
fromTree t = Loc { _content = F t, _before = [], _after = [], _parents = [] }
fromForest :: Forest a -> TreePos Empty a
fromForest ts = Loc { _content = E, _before = [], _after = ts, _parents = [] }
toTree :: TreePos Full a -> Tree a
toTree loc = tree (root loc)
toForest :: PosType t => TreePos t a -> Forest a
toForest loc = case parent loc of
Nothing -> forest loc
Just p -> toForest p
isRoot :: PosType t => TreePos t a -> Bool
isRoot loc = null (parents loc)
isFirst :: PosType t => TreePos t a -> Bool
isFirst loc = null (before loc)
isLast :: PosType t => TreePos t a -> Bool
isLast loc = null (after loc)
isLeaf :: TreePos Full a -> Bool
isLeaf loc = null (subForest (tree loc))
isContained :: PosType t => TreePos t a -> Bool
isContained loc = not (isRoot loc)
hasChildren :: TreePos Full a -> Bool
hasChildren loc = not (isLeaf loc)
tree :: TreePos Full a -> Tree a
tree x = unF (_content x)
label :: TreePos Full a -> a
label loc = rootLabel (tree loc)
insert :: Tree a -> TreePos Empty a -> TreePos Full a
insert t loc = loc { _content = F t }
delete :: TreePos Full a -> TreePos Empty a
delete loc = loc { _content = E }
setTree :: Tree a -> TreePos Full a -> TreePos Full a
setTree t loc = loc { _content = F t }
modifyTree :: (Tree a -> Tree a) -> TreePos Full a -> TreePos Full a
modifyTree f loc = setTree (f (tree loc)) loc
modifyLabel :: (a -> a) -> TreePos Full a -> TreePos Full a
modifyLabel f loc = setLabel (f (label loc)) loc
setLabel :: a -> TreePos Full a -> TreePos Full a
setLabel v loc = modifyTree (\t -> t { rootLabel = v }) loc