transformations-0.1.1.0: Generics/Regular/Zipper.hs
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE TupleSections #-}
module Generics.Regular.Zipper
(-- * Locations
Loc(..),
-- * Context frames
Ctx(),
-- * Generic zipper class
Zipper(..),
-- * Interface
enter,
down, down', up, right, left,
-- dfnext, dfprev,
leave, on, update, updateM
)
where
import Prelude hiding (last)
import Control.Monad
import Control.Monad.State
import Control.Applicative
import Data.Maybe
import Data.Traversable
import Generics.Regular hiding (left, right)
-- * Locations and context stacks
-- | Abstract type of locations. A location contains the current focus
-- and its context. A location is parameterized over the family of
-- datatypes and over the type of the complete value.
data Loc :: * -> * where
Loc :: (Regular a, Zipper (PF a)) => a -> [Ctx (PF a) a] -> Loc a
-- * Context frames
-- | Abstract type of context frames. Not required for the high-level
-- navigation functions.
data family Ctx (f :: * -> *) :: * -> *
data instance Ctx (K a) r
data instance Ctx U r
data instance Ctx (f :+: g) r = CL (Ctx f r) | CR (Ctx g r)
data instance Ctx (f :*: g) r = C1 (Ctx f r) (g r) | C2 (f r) (Ctx g r)
data instance Ctx I r = CId
data instance Ctx (C c f) r = CC (Ctx f r)
data instance Ctx (S s f) r = CS (Ctx f r)
-- * Contexts and locations are functors
instance Zipper f => Functor (Ctx f) where
fmap = cmap
-- instance Functor (Loc f) where
-- fmap f (Loc p x) = Loc (f p) (map (fmap f) x)
-- * Generic navigation functions
-- | It is in general not necessary to use the generic navigation
-- functions directly. The functions listed in the ``Interface'' section
-- below are more user-friendly.
--
class Functor f => Zipper f where
cmap :: (a -> b) -> Ctx f a -> Ctx f b
fill :: Ctx f a -> a -> f a
first, last :: f a -> Maybe (a, Ctx f a)
next, prev :: Ctx f a -> a -> Maybe (a, Ctx f a)
instance Zipper I where
cmap f CId = CId
fill CId x = I x
first (I x) = Just (x, CId)
last (I x) = Just (x, CId)
next CId x = Nothing
prev CId x = Nothing
instance Zipper (K a) where
cmap f void = impossible void
fill void x = impossible void
first (K a) = Nothing
last (K a) = Nothing
next void x = impossible void
prev void x = impossible void
instance Zipper U where
cmap f void = impossible void
fill void x = impossible void
first U = Nothing
last U = Nothing
next void x = impossible void
prev void x = impossible void
instance (Zipper f, Zipper g) => Zipper (f :+: g) where
cmap f (CL c) = CL (cmap f c)
cmap f (CR c) = CR (cmap f c)
fill (CL c) x = L (fill c x)
fill (CR c) y = R (fill c y)
first (L x) = first x >>= return . fmap CL
first (R x) = first x >>= return . fmap CR
last (L x) = last x >>= return . fmap CL
last (R x) = last x >>= return . fmap CR
next (CL c) x = next c x >>= return . fmap CL
next (CR c) x = next c x >>= return . fmap CR
prev (CL c) x = prev c x >>= return . fmap CL
prev (CR c) x = prev c x >>= return . fmap CR
instance (Zipper f, Zipper g) => Zipper (f :*: g) where
cmap f (C1 c y) = C1 (cmap f c) (fmap f y)
cmap f (C2 x c) = C2 (fmap f x) (cmap f c)
fill (C1 c y) x = fill c x :*: y
fill (C2 x c) y = x :*: fill c y
first (x :*: y) = fmap (fmap (flip C1 y)) (first x)
`mplus` fmap (fmap (C2 x)) (first y)
last (x :*: y) = fmap (fmap (C2 x)) (last y)
`mplus` fmap (fmap (flip C1 y)) (last x)
next (C1 c y) z = (fmap (flip C1 y) <$> next c z)
`mplus` (fmap (C2 (fill c z)) <$> first y)
next (C2 x c) z = fmap (C2 x) <$> next c z
prev (C1 c y) z = fmap (flip C1 y) <$> prev c z
prev (C2 x c) z = (fmap (C2 x) <$> prev c z)
`mplus` (fmap (flip C1 (fill c z)) <$> last x)
instance (Zipper f) => Zipper (C c f) where
cmap f (CC c) = CC (cmap f c)
fill (CC c) x = C (fill c x)
first (C x) = first x >>= return . fmap CC
last (C x) = last x >>= return . fmap CC
next (CC c) x = next c x >>= return . fmap CC
prev (CC c) x = prev c x >>= return . fmap CC
instance (Zipper f) => Zipper (S s f) where
cmap f (CS c) = CS (cmap f c)
fill (CS c) x = S (fill c x)
first (S x) = first x >>= return . fmap CS
last (S x) = last x >>= return . fmap CS
next (CS c) x = next c x >>= return . fmap CS
prev (CS c) x = prev c x >>= return . fmap CS
-- * Interface
-- ** Introduction
-- | Start navigating a datastructure. Returns a location that
-- focuses the entire value and has an empty context.
enter :: (Regular a, Zipper (PF a)) => a -> Loc a
enter x = Loc x []
-- ** Navigation
-- | Move down to the leftmost child. Returns 'Nothing' if the
-- current focus is a leaf.
down :: Loc a -> Maybe (Loc a)
down (Loc x cs) = first (from x) >>= \(a,c) -> return (Loc a (c:cs))
-- | Move down to the rightmost child. Returns 'Nothing' if the
-- current focus is a leaf.
down' :: Loc a -> Maybe (Loc a)
down' (Loc x cs) = last (from x) >>= \(a,c) -> return (Loc a (c:cs))
-- | Move up to the parent. Returns 'Nothing' if the current
-- focus is the root.
up :: Loc a -> Maybe (Loc a)
up (Loc x []) = Nothing
up (Loc x (c:cs)) = return (Loc (to (fill c x)) cs)
-- | Move to the right sibling. Returns 'Nothing' if the current
-- focus is the rightmost sibling.
right :: Loc a -> Maybe (Loc a)
right (Loc x [] ) = Nothing
right (Loc x (c:cs)) = next c x >>= \(a,c') -> return (Loc a (c':cs))
-- | Move to the left sibling. Returns 'Nothing' if the current
-- focus is the leftmost sibling.
left :: Loc a -> Maybe (Loc a)
left (Loc x [] ) = Nothing
left (Loc x (c:cs)) = prev c x >>= \(a,c') -> return (Loc a (c':cs))
-- ** Derived navigation.
{-
df :: (a -> Maybe a) -> (a -> Maybe a) -> (a -> Maybe a) -> a -> Maybe a
df d u lr l =
case d l of
Nothing -> df' l
r -> r
where
df' l =
case lr l of
Nothing -> case u l of
Nothing -> Nothing
Just l' -> df' l'
r -> r
-- | Move through all positions in depth-first left-to-right order.
dfnext :: Loc phi I0 ix -> Maybe (Loc phi I0 ix)
dfnext = df down up right
-- | Move through all positions in depth-first right-to-left order.
dfprev :: Loc phi I0 ix -> Maybe (Loc phi I0 ix)
dfprev = df down' up left
-}
-- | Utility
-- navigate :: (Regular a, Zipper (PF a))
-- => a -> (Loc a -> Maybe (Loc a)) -> Loc a
-- navigate a f = fromJust $ f (enter a)
-- ** Elimination
-- | Return the entire value, independent of the current focus.
leave :: Loc a -> a
leave (Loc x []) = x
leave loc = leave (fromJust (up loc))
-- | Operate on the current focus. This function can be used to
-- extract the current point of focus.
on :: Loc a -> a
on (Loc x _) = x
-- | Update the current focus without changing its type.
update :: (a -> a) -> Loc a -> Loc a
update f (Loc x cs) = Loc (f x) cs
-- | Update the current focus without changing its type.
updateM :: Monad m => (a -> m a) -> Loc a -> m (Loc a)
updateM f (Loc x cs) = f x >>= \y -> return (Loc y cs)
-- * Internal functions
impossible :: a -> b
impossible x = x `seq` error "impossible"