{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} module Zipper where import Prelude hiding (last) import Control.Monad import Data.Maybe import Base import TEq import Void -- * Locations and context stacks data Loc :: (* -> *) -> * -> * where Loc :: (Ix s ix, Zipper (PF s)) => ix -> Ctxs s a ix -> Loc s a data Ctxs :: (* -> *) -> * -> * -> * where Empty :: Ctxs s a a Push :: Ix s ix => Ctx (PF s) s ix b -> Ctxs s a ix -> Ctxs s a b -- * Context frames data family Ctx f :: (* -> *) -> * -> * -> * data instance Ctx (K a) s ix b = CK Void data instance Ctx (f :+: g) s ix b = CL (Ctx f s ix b) | CR (Ctx g s ix b) data instance Ctx (f :*: g) s ix b = C1 (Ctx f s ix b) (g s I0 ix) | C2 (f s I0 ix) (Ctx g s ix b) -- The equality constraints simulate GADTs. GHC currently -- does not allow us to use GADTs as data family instances. data instance Ctx (I xi) s ix b = CId (b :=: xi) data instance Ctx (f :>: xi) s ix b = CTag (ix :=: xi) (Ctx f s ix b) -- * Generic navigation functions class Zipper f where fill :: Ix s b => Ctx f s ix b -> b -> f s I0 ix first, last :: (forall b. Ix s b => b -> Ctx f s ix b -> a) -> f s I0 ix -> Maybe a next, prev :: (forall b. Ix s b => b -> Ctx f s ix b -> a) -> Ix s b => Ctx f s ix b -> b -> Maybe a instance Zipper (I xi) where fill (CId prf) x = castId prf (I . I0) x first f (I (I0 x)) = return (f x (CId Refl)) last f (I (I0 x)) = return (f x (CId Refl)) next f (CId prf) x = Nothing prev f (CId prf) x = Nothing instance Zipper (K a) where fill (CK void) x = impossible void first f (K a) = Nothing last f (K a) = Nothing next f (CK void) x = impossible void prev f (CK void) x = impossible void instance (Zipper f, Zipper g) => Zipper (f :+: g) where fill (CL c) x = L (fill c x) fill (CR c) y = R (fill c y) first f (L x) = first (\z -> f z . CL) x first f (R y) = first (\z -> f z . CR) y last f (L x) = last (\z -> f z . CL) x last f (R y) = last (\z -> f z . CR) y next f (CL c) x = next (\z -> f z . CL) c x next f (CR c) y = next (\z -> f z . CR) c y prev f (CL c) x = prev (\z -> f z . CL) c x prev f (CR c) y = prev (\z -> f z . CR) c y instance (Zipper f, Zipper g) => Zipper (f :*: g) where fill (C1 c y) x = fill c x :*: y fill (C2 x c) y = x :*: fill c y first f (x :*: y) = first (\z c -> f z (C1 c y )) x `mplus` first (\z c -> f z (C2 x c )) y last f (x :*: y) = last (\z c -> f z (C2 x c )) y `mplus` last (\z c -> f z (C1 c y )) x next f (C1 c y) x = next (\z c' -> f z (C1 c' y )) c x `mplus` first (\z c' -> f z (C2 (fill c x) c')) y next f (C2 x c) y = next (\z c' -> f z (C2 x c')) c y prev f (C1 c y) x = prev (\z c' -> f z (C1 c' y )) c x prev f (C2 x c) y = prev (\z c' -> f z (C2 x c')) c y `mplus` last (\z c' -> f z (C1 c' (fill c y))) x instance Zipper f => Zipper (f :>: xi) where fill (CTag prf c) x = castTag prf Tag (fill c x) first f (Tag x) = first (\z -> f z . CTag Refl) x last f (Tag x) = last (\z -> f z . CTag Refl) x next f (CTag prf c) x = next (\z -> f z . CTag prf) c x prev f (CTag prf c) x = prev (\z -> f z . CTag prf) c x -- Helping the typechecker to apply equality proofs correctly ... castId :: (b :=: xi) -> (Ix s xi => xi -> I xi s I0 ix) -> (Ix s b => b -> I xi s I0 ix) castTag :: (ix :=: xi) -> (f s I0 ix -> (f :>: ix) s I0 ix) -> (f s I0 ix -> (f :>: xi) s I0 ix) castId Refl f = f castTag Refl f = f -- * Interface enter :: (Ix s ix, Zipper (PF s)) => s ix -> ix -> Loc s ix down, down', up :: Loc s ix -> Maybe (Loc s ix) right, left :: Loc s ix -> Maybe (Loc s ix) leave :: Loc s ix -> ix on :: (forall xi. s xi -> xi -> a) -> Loc s ix -> a update :: (forall xi. s xi -> xi -> xi) -> Loc s ix -> Loc s ix enter _ x = Loc x Empty down (Loc x s ) = first (\z c -> Loc z (Push c s)) (from x) down' (Loc x s ) = last (\z c -> Loc z (Push c s)) (from x) up (Loc x Empty ) = Nothing up (Loc x (Push c s)) = return (Loc (to (fill c x)) s) right (Loc x Empty ) = Nothing right (Loc x (Push c s)) = next (\z c' -> Loc z (Push c' s)) c x left (Loc x Empty ) = Nothing left (Loc x (Push c s)) = prev (\z c' -> Loc z (Push c' s)) c x leave (Loc x Empty) = x leave loc = leave (fromJust (up loc)) on f (Loc x _ ) = f index x update f (Loc x s ) = Loc (f index x) s