debruijn-0.1: src/DeBruijn/Internal/Idx.hs
{-# LANGUAGE Unsafe #-}
-- | de Bruijn indices for well-scoped terms.
module DeBruijn.Internal.Idx (
-- * de Bruijn indices
Idx (IZ, IS, UnsafeIdx),
absurdIdx,
unIdx,
idxToInt,
-- * Common indices
pattern I1,
pattern I2,
pattern I3,
pattern I4,
pattern I5,
pattern I6,
pattern I7,
pattern I8,
pattern I9,
) where
import Data.Kind (Type)
import DeBruijn.Ctx
import Unsafe.Coerce (unsafeCoerce)
-------------------------------------------------------------------------------
-- de Bruijn indices
-------------------------------------------------------------------------------
-- | de Bruijn indices.
--
-- >>> IS (IS (IS IZ))
-- 3
--
type Idx :: Ctx -> Type
type role Idx nominal
newtype Idx j = UnsafeIdx { _idxToInt :: Int }
-------------------------------------------------------------------------------
-- Combinators
-------------------------------------------------------------------------------
-- | Convert index to 'Int'.
idxToInt :: Idx ctx -> Int
idxToInt = _idxToInt
-- | Derive anything from index into empty scope.
--
-- Note: don't use @EmptyCase@ on 'Idx' as it doesn't work for unsafe representation.
--
absurdIdx :: Idx EmptyCtx -> a
absurdIdx x = x `seq` error "absurd: Idx Z"
-------------------------------------------------------------------------------
-- Pattern synonyms
-------------------------------------------------------------------------------
-- We need a GADT to implement pattern synonyms.
type ViewIdx :: Ctx -> Type
type role ViewIdx nominal
data ViewIdx n where
IZ' :: ViewIdx (S n)
IS' :: Idx n -> ViewIdx (S n)
viewIdx :: Idx n -> ViewIdx n
viewIdx (UnsafeIdx 0) = unsafeCoerce IZ'
viewIdx (UnsafeIdx n) = unsafeCoerce (IS' (UnsafeIdx (n - 1)))
pattern IZ :: () => (m ~ S n) => Idx m
pattern IZ <- (viewIdx -> IZ')
where IZ = UnsafeIdx 0
pattern IS :: () => (m ~ S n) => Idx n -> Idx m
pattern IS n <- (viewIdx -> IS' n)
where IS n = UnsafeIdx (idxToInt n + 1)
{-# COMPLETE IZ, IS #-}
-------------------------------------------------------------------------------
-- Instances
-------------------------------------------------------------------------------
deriving instance Eq (Idx n)
deriving instance Ord (Idx n)
instance Show (Idx j) where
showsPrec d = showsPrec d . idxToInt
-------------------------------------------------------------------------------
-- Common Combinators
-------------------------------------------------------------------------------
-- | Case on 'Idx'. (compare to 'maybe').
unIdx :: a -> (Idx n -> a) -> Idx (S n) -> a
unIdx z _ IZ = z
unIdx _ s (IS x) = s x
pattern I1 :: () => (m ~ S (S n)) => Idx m
pattern I1 = IS IZ
pattern I2 :: () => (m ~ S (S (S n))) => Idx m
pattern I2 = IS I1
pattern I3 :: () => (m ~ S (S (S (S n)))) => Idx m
pattern I3 = IS I2
pattern I4 :: () => (m ~ S (S (S (S (S n))))) => Idx m
pattern I4 = IS I3
pattern I5 :: () => (m ~ S (S (S (S (S (S n)))))) => Idx m
pattern I5 = IS I4
pattern I6 :: () => (m ~ S (S (S (S (S (S (S n))))))) => Idx m
pattern I6 = IS I5
pattern I7 :: () => (m ~ S (S (S (S (S (S (S (S n)))))))) => Idx m
pattern I7 = IS I6
pattern I8 :: () => (m ~ S (S (S (S (S (S (S (S (S n))))))))) => Idx m
pattern I8 = IS I7
pattern I9 :: () => (m ~ S (S (S (S (S (S (S (S (S (S n)))))))))) => Idx m
pattern I9 = IS I8