{-# LANGUAGE Safe #-} module DeBruijn.Lvl ( Lvl, lvlToIdx, lvlZ, sinkLvl, Sinkable (..), sink, mapSink, sinkSize, mapSinkSize, sinkAdd, mapSinkAdd, ) where import Data.Kind (Constraint, Type) import DeBruijn.Add import DeBruijn.Ctx import DeBruijn.Idx import DeBruijn.Lte import DeBruijn.Size -- $setup -- >>> import DeBruijn -- >>> import DeBruijn.Lte ------------------------------------------------------------------------------- -- de Bruijn levels ------------------------------------------------------------------------------- -- | de Bruijn levels. -- -- type Lvl :: Ctx -> Type type role Lvl nominal data Lvl ctx = MkLvl !Int !(Idx ctx) deriving (Eq, Ord) -- Note: we need an integer field for Show instance. ------------------------------------------------------------------------------- -- Instances ------------------------------------------------------------------------------- instance Show (Lvl ctx) where showsPrec d (MkLvl i _) = showsPrec d i ------------------------------------------------------------------------------- -- Helpers ------------------------------------------------------------------------------- -- | Convert level to index. -- -- >>> lvlToIdx S2 (lvlZ S1) -- 0 -- lvlToIdx :: Size ctx -> Lvl ctx -> Idx ctx lvlToIdx _ (MkLvl _ x) = x -- | Last level. -- -- >>> lvlZ S1 -- 1 -- -- >>> lvlZ S5 -- 5 -- lvlZ :: Size ctx -> Lvl (S ctx) lvlZ s = MkLvl (sizeToInt s) IZ -- | Sink 'Lvl' into a larger context. -- -- >>> sinkLvl (lvlZ S3) -- 3 -- -- >>> sink (lvlZ S3) -- 3 -- -- >>> mapLvl (LS LZ) (lvlZ S3) -- 3 -- -- sinkLvl :: Lvl ctx -> Lvl (S ctx) sinkLvl (MkLvl s i) = MkLvl s (IS i) ------------------------------------------------------------------------------- -- Sinkable ------------------------------------------------------------------------------- -- | Sinkable terms can be weakened (sunk) cheaply. -- (when 'Lvl' is implemented as newtype over 'Int'). type Sinkable :: (Ctx -> Type) -> Constraint class Sinkable t where mapLvl :: Lte ctx ctx' -> t ctx -> t ctx' lteLvl :: Lte ctx ctx' -> Lvl ctx -> Lvl ctx' lteLvl LZ t = t lteLvl (LS l) (MkLvl s i) = MkLvl s (lteIdx (LS l) i) lteIdx :: Lte ctx ctx' -> Idx ctx -> Idx ctx' lteIdx LZ i = i lteIdx (LS s) i = IS (lteIdx s i) instance Sinkable Lvl where mapLvl = lteLvl sink :: Sinkable t => t ctx -> t (S ctx) sink = mapLvl (LS LZ) mapSink :: (Functor f, Sinkable t) => f (t ctx) -> f (t (S ctx)) mapSink = fmap sink sinkSize :: Sinkable t => Size ctx -> t EmptyCtx -> t ctx sinkSize SZ t = t sinkSize (SS n) t = sink (sinkSize n t) mapSinkSize :: (Functor f, Sinkable t) => Size ctx -> f (t EmptyCtx) -> f (t ctx) mapSinkSize = fmap . sinkSize sinkAdd :: Sinkable t => Add n ctx ctx' -> t ctx -> t ctx' sinkAdd AZ t = t sinkAdd (AS s) t = sink (sinkAdd s t) mapSinkAdd :: (Functor f, Sinkable t) => Add n ctx ctx' -> f (t ctx) -> f (t ctx') mapSinkAdd = fmap . sinkAdd