packages feed

data-debruijn-0.1.0.0: src-safe/Data/DeBruijn/Environment/Safe.hs

{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE ExplicitNamespaces #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE QuantifiedConstraints #-}

module Data.DeBruijn.Environment.Safe (
  Env (Nil, (:>)),
  decEnvLen,
  (!),
) where

import Control.DeepSeq (NFData (..))
import Data.DeBruijn.Index.Safe (Ix (FS, FZ), isPos)
import Data.Kind (Type)
import Data.Type.Equality ((:~:) (Refl))
import Data.Type.Nat (type Nat (..))
import Prelude hiding (lookup)

-- | @'Env' n@ is the type of environments with @n@ elements.
type Env :: Nat -> Type -> Type
data Env n a where
  Nil :: Env Z a
  (:>) :: Env n a -> a -> Env (S n) a

deriving stock instance Functor (Env n)

deriving stock instance Foldable (Env n)

deriving stock instance Traversable (Env n)

decEnvLen :: Env n a -> Env m a -> Maybe (n :~: m)
decEnvLen Nil Nil = Just Refl
decEnvLen (xs :> _x) (ys :> _y) = (\Refl -> Refl) <$> decEnvLen xs ys
decEnvLen _ _ = Nothing

instance (NFData a) => NFData (Env n a) where
  rnf :: Env n a -> ()
  rnf Nil = ()
  rnf (xs :> x) = rnf x `seq` rnf xs

instance (Eq a) => Eq (Env n a) where
  (==) :: Env n a -> Env n a -> Bool
  Nil == Nil = True
  xs :> x == ys :> y = x == y && xs == ys

deriving instance (Show a) => Show (Env n a)

(!) :: Env n a -> Ix n -> a
xs ! i = isPos i $ case (xs, i) of
  (_ys :> y, FZ) -> y
  (ys :> _y, FS j) -> ys ! j