plutils

programming language utilities
git clone git://git.rr3.xyz/plutils
Log | Files | Refs | Submodules

commit 0d9ba56d82d9a5993d54fb79f38c4e39af7f1b8e
parent eadfc1b82c261148bc2028ad639c22764fe5421a
Author: Robert Russell <robert@rr3.xyz>
Date:   Sat, 26 Jul 2025 18:35:14 -0700

Uncomment and simplify environments

Diffstat:
Mpackage.yaml | 1+
Msrc/PlUtils/DeBruijn.hs | 46++++++++++++++++++++++++++++++++++++++--------
Msrc/PlUtils/Environment.hs | 76+++++++++++++++++++++-------------------------------------------------------
Asrc/PlUtils/Util.hs | 8++++++++
4 files changed, 68 insertions(+), 63 deletions(-)

diff --git a/package.yaml b/package.yaml @@ -18,6 +18,7 @@ default-extensions: - MagicHash - OverloadedStrings - PartialTypeSignatures + - PatternSynonyms - QuantifiedConstraints - RecursiveDo - TypeData diff --git a/src/PlUtils/DeBruijn.hs b/src/PlUtils/DeBruijn.hs @@ -1,24 +1,54 @@ module PlUtils.DeBruijn ( + Depth (..), Index (..), Level (..), + descend, + idxInBounds, + lvlInBounds, + assertIdxInBounds, + assertLvlInBounds, idxToLvl, lvlToIdx, ) where -import Data.Coerce -import Naturals +import Naturals.Nat + +import PlUtils.Util -------------------------------------------------------------------------------- -- Indices and levels -newtype Index n = Index (Finat n) -newtype Level n = Level (Finat n) +-- | A @Nat@ representing the number of free variables in some context. +newtype Depth = Depth {unDepth :: Nat} deriving (Show, Eq) + +-- | A de Bruijn index represented as a @Nat@, that is, an index into a context +-- "from the right", such that the innermost free variable gets index 0. +newtype Index = Index {unIndex :: Nat} deriving (Show, Eq) + +-- | A de Bruijn level represented as a @Nat@, that is, an index into a context +-- "from the left", such that the outermost free variable gets index 0. +newtype Level = Level {unLevel :: Nat} deriving (Show, Eq) + +descend :: Depth -> (Level, Depth) +descend (Depth d) = assert (d < maxBound) "PlUtils: depth overflow" (Level d, Depth (d + 1)) + +idxInBounds :: Depth -> Index -> Bool +idxInBounds (Depth d) (Index i) = i < d + +lvlInBounds :: Depth -> Level -> Bool +lvlInBounds (Depth d) (Level l) = l < d + +assertIdxInBounds :: Depth -> Index -> a -> a +assertIdxInBounds d i = assert (idxInBounds d i) "PlUtils: index out of bounds" + +assertLvlInBounds :: Depth -> Level -> a -> a +assertLvlInBounds d l = assert (lvlInBounds d l) "PlUtils: level out of bounds" -idxToLvl :: Snat n -> Index n -> Level n -idxToLvl = coerce finatMirror +idxToLvl :: Depth -> Index -> Level +idxToLvl d i = assertIdxInBounds d i $ Level (unDepth d - unIndex i - 1) -lvlToIdx :: Snat n -> Level n -> Index n -lvlToIdx = coerce finatMirror +lvlToIdx :: Depth -> Level -> Index +lvlToIdx d l = assertLvlInBounds d l $ Index (unDepth d - unLevel l - 1) -------------------------------------------------------------------------------- -- TODO diff --git a/src/PlUtils/Environment.hs b/src/PlUtils/Environment.hs @@ -1,82 +1,48 @@ -module PlUtils.Environment where - -{- module PlUtils.Environment ( Environment, empty, depth, bind, - idxToLvl, - lvlToIdx, assign, lookup, define, - eval, ) where -import Control.Exception hiding (assert) -import Data.IntMap.Strict (IntMap) -import Data.IntMap.Strict qualified as IntMap -import Data.Maybe (fromMaybe) +import Naturals.NatMap (NatMap) +import Naturals.NatMap qualified as NatMap import Prelude hiding (lookup) import PlUtils.DeBruijn --- We really ought to use natural numbers here instead of integers, but Haskell --- makes that difficult (e.g., fixed-precision natural number types are called --- "WordXX" instead of "NatXX", and there's IntMap but not NatMap). - -assert :: Bool -> String -> a -> a -assert b s a = if b then a else throw (AssertionFailed s) - -- | A collection of free variables and a substitution on them, intended for --- semantic elaboration and evaluation with semantic variables represented as --- de Bruijn levels (which are stable under weakening, so we don't need to --- modify the environment when descending under a binder) and with syntactic --- variables represented as de Bruijn indices. -data Environment idx val = Environment Int (IntMap val) deriving (Show) +-- evaluation with semantic variables represented as de Bruijn levels (which are +-- stable under weakening, so we don't need to modify the environment when +-- descending under a binder) and with syntactic variables represented as +-- de Bruijn indices. +data Environment v = Environment Depth (NatMap v) deriving (Show) -empty :: (IsIndex idx, SemValue val) => Environment idx val -empty = Environment 0 IntMap.empty +empty :: Environment v +empty = Environment (Depth 0) NatMap.empty -depth :: (IsIndex idx, SemValue val) => Environment idx val -> Int +depth :: Environment v -> Depth depth (Environment d _) = d -- | Bind a new variable (without introducing a substitution for it). -bind :: (IsIndex idx, SemValue val) => Environment idx val -> (Level val, Environment idx val) -bind (Environment d s) = assert (d < maxBound) "PlUtils.Environment.bind: depth overflow" (intToLvl d, Environment (d + 1) s) - -idxToLvl :: (IsIndex idx, SemValue val) => idx -> Environment idx val -> Level val -idxToLvl idx (Environment d _) = - let i = idxToInt idx - in assert (0 <= i && i < d) "PlUtils.Environment.idxToLvl: index out of range" $ intToLvl (d - i - 1) - -lvlToIdx :: (IsIndex idx, SemValue val) => Level val -> Environment idx val -> idx -lvlToIdx lvl (Environment d _) = - let l = lvlToInt lvl - in assert (0 <= l && l < d) "PlUtils.Environment.lvlToIdx: level out of range" $ intToIdx (d - l - 1) +bind :: Environment v -> (Level, Environment v) +bind (Environment d s) = + let (l, d') = descend d + in (l, Environment d' s) -- | Assign a value to an existing variable. -assign :: (IsIndex idx, SemValue val) => Level val -> val -> Environment idx val -> Environment idx val -assign lvl val (Environment d s) = - let l = lvlToInt lvl - in assert (0 <= l && l < d) "PlUtils.Environment.assign: level out of range" $ Environment d (IntMap.insert l val s) +assign :: Level -> v -> Environment v -> Environment v +assign l v (Environment d s) = assertLvlInBounds d l $ Environment d (NatMap.insert (unLevel l) v s) -- | Lookup the substitution for a variable. -lookup :: (IsIndex idx, SemValue val) => Level val -> Environment idx val -> Maybe val -lookup lvl (Environment d s) = - let l = lvlToInt lvl - in assert (0 <= l && l < d) "PlUtils.Environment.lookup: level out of range" $ IntMap.lookup l s +lookup :: Level -> Environment v -> Maybe v +lookup l (Environment d s) = assertLvlInBounds d l $ NatMap.lookup (unLevel l) s -- | Bind and a new variable and assign a value to it. -define :: (IsIndex idx, SemValue val) => (Level val -> val) -> Environment idx val -> Environment idx val +define :: (Level -> v) -> Environment v -> Environment v define makeVal env = - let (lvl, env') = bind env - in assign lvl (makeVal lvl) env' - --- | Lookup the substitution for a variable. -eval :: (IsIndex idx, SemValue val) => idx -> Environment idx val -> val -eval idx env = - let lvl = idxToLvl idx env - in fromMaybe (generic lvl) (lookup lvl env) --} + let (l, env') = bind env + in assign l (makeVal l) env' diff --git a/src/PlUtils/Util.hs b/src/PlUtils/Util.hs @@ -0,0 +1,8 @@ +module PlUtils.Util ( + assert, +) where + +import Control.Exception hiding (assert) + +assert :: Bool -> String -> a -> a +assert b s a = if b then a else throw (AssertionFailed s)