---------------------------------------------------------------------- -- | -- Module : Zipper -- Maintainer : AR -- Stability : (stable) -- Portability : (portable) -- -- > CVS $Date: 2005/06/11 20:27:05 $ -- > CVS $Author: aarne $ -- > CVS $Revision: 1.9 $ -- -- Gérard Huet's zipper (JFP 7 (1997)). AR 10\/8\/2001 ----------------------------------------------------------------------------- module GF.Data.Zipper (-- * types Tr(..), Path(..), Loc(..), -- * basic (original) functions leaf, goLeft, goRight, goUp, goDown, changeLoc, changeNode, forgetNode, -- * added sequential representation goAhead, goBack, -- ** n-ary versions goAheadN, goBackN, -- * added mappings between locations and trees loc2tree, loc2treeMarked, tree2loc, goRoot, goLast, goPosition, getPosition, keepPosition, -- * added some utilities traverseCollect, scanTree, mapTr, mapTrM, mapPath, mapPathM, mapLoc, mapLocM, foldTr, foldTrM, mapSubtrees, mapSubtreesM, changeRoot, nthSubtree, arityTree ) where import GF.Data.Operations newtype Tr a = Tr (a,[Tr a]) deriving (Show,Eq) data Path a = Top | Node ([Tr a], (Path a, a), [Tr a]) deriving Show leaf :: a -> Tr a leaf a = Tr (a,[]) newtype Loc a = Loc (Tr a, Path a) deriving Show goLeft, goRight, goUp, goDown :: Loc a -> Err (Loc a) goLeft (Loc (t,p)) = case p of Top -> Bad "left of top" Node (l:left, upv, right) -> return $ Loc (l, Node (left,upv,t:right)) Node _ -> Bad "left of first" goRight (Loc (t,p)) = case p of Top -> Bad "right of top" Node (left, upv, r:right) -> return $ Loc (r, Node (t:left,upv,right)) Node _ -> Bad "right of first" goUp (Loc (t,p)) = case p of Top -> Bad "up of top" Node (left, (up,v), right) -> return $ Loc (Tr (v, reverse left ++ (t:right)), up) goDown (Loc (t,p)) = case t of Tr (v,(t1:trees)) -> return $ Loc (t1,Node ([],(p,v),trees)) _ -> Bad "down of empty" changeLoc :: Loc a -> Tr a -> Err (Loc a) changeLoc (Loc (_,p)) t = return $ Loc (t,p) changeNode :: (a -> a) -> Loc a -> Loc a changeNode f (Loc (Tr (n,ts),p)) = Loc (Tr (f n, ts),p) forgetNode :: Loc a -> Err (Loc a) forgetNode (Loc (Tr (n,[t]),p)) = return $ Loc (t,p) forgetNode _ = Bad $ "not a one-branch tree" -- added sequential representation -- | a successor function goAhead :: Loc a -> Err (Loc a) goAhead s@(Loc (t,p)) = case (t,p) of (Tr (_,_:_),Node (_,_,_:_)) -> goDown s (Tr (_,[]), _) -> upsRight s (_, _) -> goDown s where upsRight t = case goRight t of Ok t' -> return t' Bad _ -> goUp t >>= upsRight -- | a predecessor function goBack :: Loc a -> Err (Loc a) goBack s@(Loc (t,p)) = case goLeft s of Ok s' -> downRight s' _ -> goUp s where downRight s = case goDown s of Ok s' -> case goRight s' of Ok s'' -> downRight s'' _ -> downRight s' _ -> return s -- n-ary versions goAheadN :: Int -> Loc a -> Err (Loc a) goAheadN i st | i < 1 = return st | otherwise = goAhead st >>= goAheadN (i-1) goBackN :: Int -> Loc a -> Err (Loc a) goBackN i st | i < 1 = return st | otherwise = goBack st >>= goBackN (i-1) -- added mappings between locations and trees loc2tree :: Loc a -> Tr a loc2tree (Loc (t,p)) = case p of Top -> t Node (left,(p',v),right) -> loc2tree (Loc (Tr (v, reverse left ++ (t : right)),p')) loc2treeMarked :: Loc a -> Tr (a, Bool) loc2treeMarked (Loc (Tr (a,ts),p)) = loc2tree (Loc (Tr (mark a, map (mapTr nomark) ts), mapPath nomark p)) where (mark, nomark) = (\a -> (a,True), \a -> (a, False)) tree2loc :: Tr a -> Loc a tree2loc t = Loc (t,Top) goRoot :: Loc a -> Loc a goRoot = tree2loc . loc2tree goLast :: Loc a -> Err (Loc a) goLast = rep goAhead where rep f s = err (const (return s)) (rep f) (f s) goPosition :: [Int] -> Loc a -> Err (Loc a) goPosition p = go p . goRoot where go [] s = return s go (p:ps) s = goDown s >>= apply p goRight >>= go ps getPosition :: Loc a -> [Int] getPosition = reverse . getp where getp (Loc (t,p)) = case p of Top -> [] Node (left,(p',v),_) -> length left : getp (Loc (Tr (v, []),p')) keepPosition :: (Loc a -> Err (Loc a)) -> (Loc a -> Err (Loc a)) keepPosition f s = do let p = getPosition s s' <- f s goPosition p s' apply :: Monad m => Int -> (a -> m a) -> a -> m a apply n f a = case n of 0 -> return a _ -> f a >>= apply (n-1) f -- added some utilities traverseCollect :: Path a -> [a] traverseCollect p = reverse $ case p of Top -> [] Node (_, (p',v), _) -> v : traverseCollect p' scanTree :: Tr a -> [a] scanTree (Tr (a,ts)) = a : concatMap scanTree ts mapTr :: (a -> b) -> Tr a -> Tr b mapTr f (Tr (x,ts)) = Tr (f x, map (mapTr f) ts) mapTrM :: Monad m => (a -> m b) -> Tr a -> m (Tr b) mapTrM f (Tr (x,ts)) = do fx <- f x fts <- mapM (mapTrM f) ts return $ Tr (fx,fts) mapPath :: (a -> b) -> Path a -> Path b mapPath f p = case p of Node (ts1, (p,v), ts2) -> Node (map (mapTr f) ts1, (mapPath f p, f v), map (mapTr f) ts2) Top -> Top mapPathM :: Monad m => (a -> m b) -> Path a -> m (Path b) mapPathM f p = case p of Node (ts1, (p,v), ts2) -> do ts1' <- mapM (mapTrM f) ts1 p' <- mapPathM f p v' <- f v ts2' <- mapM (mapTrM f) ts2 return $ Node (ts1', (p',v'), ts2') Top -> return Top mapLoc :: (a -> b) -> Loc a -> Loc b mapLoc f (Loc (t,p)) = Loc (mapTr f t, mapPath f p) mapLocM :: Monad m => (a -> m b) -> Loc a -> m (Loc b) mapLocM f (Loc (t,p)) = do t' <- mapTrM f t p' <- mapPathM f p return $ (Loc (t',p')) foldTr :: (a -> [b] -> b) -> Tr a -> b foldTr f (Tr (x,ts)) = f x (map (foldTr f) ts) foldTrM :: Monad m => (a -> [b] -> m b) -> Tr a -> m b foldTrM f (Tr (x,ts)) = do fts <- mapM (foldTrM f) ts f x fts mapSubtrees :: (Tr a -> Tr a) -> Tr a -> Tr a mapSubtrees f t = let Tr (x,ts) = f t in Tr (x, map (mapSubtrees f) ts) mapSubtreesM :: Monad m => (Tr a -> m (Tr a)) -> Tr a -> m (Tr a) mapSubtreesM f t = do Tr (x,ts) <- f t ts' <- mapM (mapSubtreesM f) ts return $ Tr (x, ts') -- | change the root without moving the pointer changeRoot :: (a -> a) -> Loc a -> Loc a changeRoot f loc = case loc of Loc (Tr (a,ts),Top) -> Loc (Tr (f a,ts),Top) Loc (t, Node (left,pv,right)) -> Loc (t, Node (left,chPath pv,right)) where chPath pv = case pv of (Top,a) -> (Top, f a) (Node (left,pv,right),v) -> (Node (left, chPath pv,right),v) nthSubtree :: Int -> Tr a -> Err (Tr a) nthSubtree n (Tr (a,ts)) = ts !? n arityTree :: Tr a -> Int arityTree (Tr (_,ts)) = length ts