| Safe Haskell | None |
|---|---|
| Language | Haskell2010 |
Control.Monad.Free.Foil
Description
This module defines a variation of free scoped (relative) monads relying on the foil for the scope-safe efficient handling of the binders.
See description of the approach in «Free Foil: Generating Efficient and Scope-Safe Abstract Syntax».
Synopsis
- data ScopedAST (binder :: S -> S -> Type) (sig :: Type -> Type -> Type) (n :: S) where
- data AST (binder :: S -> S -> Type) (sig :: Type -> Type -> Type) (n :: S) where
- substitute :: forall (sig :: Type -> Type -> Type) (o :: S) (binder :: S -> S -> Type) (i :: S). (Bifunctor sig, Distinct o, CoSinkable binder, SinkableK binder) => Scope o -> Substitution (AST binder sig) i o -> AST binder sig i -> AST binder sig o
- substituteRefreshed :: forall (sig :: Type -> Type -> Type) (o :: S) (binder :: S -> S -> Type) (i :: S). (Bifunctor sig, Distinct o, CoSinkable binder, SinkableK binder) => Scope o -> Substitution (AST binder sig) i o -> AST binder sig i -> AST binder sig o
- substitutePattern :: forall (sig :: Type -> Type -> Type) (o :: S) binder' (binder :: S -> S -> Type) (n :: S) (i :: S). (Bifunctor sig, Distinct o, CoSinkable binder', CoSinkable binder, SinkableK binder) => Scope o -> Substitution (AST binder sig) n o -> binder' n i -> [AST binder sig o] -> AST binder sig i -> AST binder sig o
- refreshAST :: forall (sig :: Type -> Type -> Type) (n :: S) (binder :: S -> S -> Type). (Bifunctor sig, Distinct n, CoSinkable binder, SinkableK binder) => Scope n -> AST binder sig n -> AST binder sig n
- refreshScopedAST :: forall (sig :: Type -> Type -> Type) (n :: S) (binder :: S -> S -> Type). (Bifunctor sig, Distinct n, CoSinkable binder, SinkableK binder) => Scope n -> ScopedAST binder sig n -> ScopedAST binder sig n
- alphaEquivRefreshed :: forall (sig :: Type -> Type -> Type) (n :: S) (binder :: S -> S -> Type). (Bitraversable sig, ZipMatchK sig, Distinct n, UnifiablePattern binder, SinkableK binder) => Scope n -> AST binder sig n -> AST binder sig n -> Bool
- alphaEquiv :: forall (sig :: Type -> Type -> Type) (n :: S) (binder :: S -> S -> Type). (Bitraversable sig, ZipMatchK sig, Distinct n, UnifiablePattern binder, SinkableK binder) => Scope n -> AST binder sig n -> AST binder sig n -> Bool
- alphaEquivScoped :: forall (sig :: Type -> Type -> Type) (binder :: S -> S -> Type) (n :: S). (Bitraversable sig, ZipMatchK sig, Distinct n, UnifiablePattern binder, SinkableK binder) => Scope n -> ScopedAST binder sig n -> ScopedAST binder sig n -> Bool
- renamedId :: forall (n :: S) (a :: S) (b :: S). (NameBinder n a -> NameBinder n b) -> Name a -> Int
- bindPairs :: forall (sig :: Type -> Type -> Type) (binder :: S -> S -> Type) (m :: S) (l1 :: S) (l2 :: S). (Bitraversable sig, ZipMatchK sig, Distinct m, UnifiablePattern binder, SinkableK binder) => Int -> IntMap Int -> IntMap Int -> [(Int, Int)] -> Scope m -> AST binder sig l1 -> AST binder sig l2 -> Bool
- alphaEquivEnv :: forall (sig :: Type -> Type -> Type) (binder :: S -> S -> Type) (n :: S) (n1 :: S) (n2 :: S). (Bitraversable sig, ZipMatchK sig, Distinct n, UnifiablePattern binder, SinkableK binder) => Int -> IntMap Int -> IntMap Int -> Scope n -> AST binder sig n1 -> AST binder sig n2 -> Bool
- alphaEquivScopedEnv :: forall (sig :: Type -> Type -> Type) (binder :: S -> S -> Type) (n :: S) (n1 :: S) (n2 :: S). (Bitraversable sig, ZipMatchK sig, Distinct n, UnifiablePattern binder, SinkableK binder) => Int -> IntMap Int -> IntMap Int -> Scope n -> ScopedAST binder sig n1 -> ScopedAST binder sig n2 -> Bool
- unsafeEqAST :: forall (sig :: Type -> Type -> Type) (binder :: S -> S -> Type) (n :: S) (l :: S). (Bitraversable sig, ZipMatchK sig, UnifiablePattern binder, Distinct n, Distinct l) => AST binder sig n -> AST binder sig l -> Bool
- unsafeEqScopedAST :: forall (sig :: Type -> Type -> Type) (binder :: S -> S -> Type) (n :: S) (l :: S). (Bitraversable sig, ZipMatchK sig, UnifiablePattern binder, Distinct n, Distinct l) => ScopedAST binder sig n -> ScopedAST binder sig l -> Bool
- data UnresolvedName rawIdent = UnresolvedName {
- unresolvedIdent :: rawIdent
- unresolvedInScope :: [rawIdent]
- unresolvedNames :: forall sig binder rawIdent rawTerm rawPattern rawScopedTerm (n :: S). (Distinct n, Bifoldable sig, Ord rawIdent, CoSinkable binder) => (rawTerm -> Either rawIdent (sig (rawPattern, rawScopedTerm) rawTerm)) -> (forall (x :: S) z. Distinct x => Scope x -> Map rawIdent (Name x) -> rawPattern -> (forall (y :: S). DExt x y => binder x y -> Map rawIdent (Name y) -> z) -> z) -> (rawScopedTerm -> rawTerm) -> Scope n -> Map rawIdent (Name n) -> rawTerm -> [UnresolvedName rawIdent]
- tryConvertToAST :: forall sig binder rawIdent rawTerm rawPattern rawScopedTerm (n :: S). (Distinct n, Bitraversable sig, Ord rawIdent, CoSinkable binder, SinkableK binder) => (rawTerm -> Either rawIdent (sig (rawPattern, rawScopedTerm) rawTerm)) -> (forall (x :: S) z. Distinct x => Scope x -> Map rawIdent (Name x) -> rawPattern -> (forall (y :: S). DExt x y => binder x y -> Map rawIdent (Name y) -> z) -> z) -> (rawScopedTerm -> rawTerm) -> Scope n -> Map rawIdent (Name n) -> rawTerm -> Either (UnresolvedName rawIdent) (AST binder sig n)
- tryConvertToASTWith :: forall sig binder rawIdent rawTerm rawPattern rawScopedTerm (n :: S). (Distinct n, Bitraversable sig, Ord rawIdent, CoSinkable binder, SinkableK binder) => (rawTerm -> Either rawIdent (sig (rawPattern, rawScopedTerm) rawTerm)) -> (forall (x :: S) z. Distinct x => Scope x -> Map rawIdent (Name x) -> rawPattern -> (forall (y :: S). DExt x y => binder x y -> Map rawIdent (Name y) -> z) -> z) -> (rawScopedTerm -> rawTerm) -> Scope n -> Map rawIdent (Name n) -> Map rawIdent (AST binder sig n) -> rawTerm -> Either (UnresolvedName rawIdent) (AST binder sig n)
- unsafeConvertToAST :: forall (n :: S) sig rawIdent binder rawTerm rawPattern rawScopedTerm. (Distinct n, Bifunctor sig, Ord rawIdent, CoSinkable binder) => (rawTerm -> Either rawIdent (sig (rawPattern, rawScopedTerm) rawTerm)) -> (forall (x :: S) z. Distinct x => Scope x -> Map rawIdent (Name x) -> rawPattern -> (forall (y :: S). DExt x y => binder x y -> Map rawIdent (Name y) -> z) -> z) -> (rawScopedTerm -> rawTerm) -> Scope n -> Map rawIdent (Name n) -> rawTerm -> AST binder sig n
- unsafeConvertToScopedAST :: forall (n :: S) sig rawIdent binder rawTerm rawPattern rawScopedTerm. (Distinct n, Bifunctor sig, Ord rawIdent, CoSinkable binder) => (rawTerm -> Either rawIdent (sig (rawPattern, rawScopedTerm) rawTerm)) -> (forall (x :: S) z. Distinct x => Scope x -> Map rawIdent (Name x) -> rawPattern -> (forall (y :: S). DExt x y => binder x y -> Map rawIdent (Name y) -> z) -> z) -> (rawScopedTerm -> rawTerm) -> Scope n -> Map rawIdent (Name n) -> (rawPattern, rawScopedTerm) -> ScopedAST binder sig n
- convertToAST :: forall (n :: S) sig rawIdent binder rawTerm rawPattern rawScopedTerm. (Distinct n, Bifunctor sig, Ord rawIdent, CoSinkable binder) => (rawTerm -> Either rawIdent (sig (rawPattern, rawScopedTerm) rawTerm)) -> (forall (x :: S) z. Distinct x => Scope x -> Map rawIdent (Name x) -> rawPattern -> (forall (y :: S). DExt x y => binder x y -> Map rawIdent (Name y) -> z) -> z) -> (rawScopedTerm -> rawTerm) -> Scope n -> Map rawIdent (Name n) -> rawTerm -> AST binder sig n
- convertToScopedAST :: forall (n :: S) sig rawIdent binder rawTerm rawPattern rawScopedTerm. (Distinct n, Bifunctor sig, Ord rawIdent, CoSinkable binder) => (rawTerm -> Either rawIdent (sig (rawPattern, rawScopedTerm) rawTerm)) -> (forall (x :: S) z. Distinct x => Scope x -> Map rawIdent (Name x) -> rawPattern -> (forall (y :: S). DExt x y => binder x y -> Map rawIdent (Name y) -> z) -> z) -> (rawScopedTerm -> rawTerm) -> Scope n -> Map rawIdent (Name n) -> (rawPattern, rawScopedTerm) -> ScopedAST binder sig n
- convertFromAST :: forall sig rawPattern rawScopedTerm rawTerm rawIdent binder (n :: S). Bifunctor sig => (sig (rawPattern, rawScopedTerm) rawTerm -> rawTerm) -> (rawIdent -> rawTerm) -> (forall (x :: S) (y :: S). binder x y -> rawPattern) -> (rawTerm -> rawScopedTerm) -> (Int -> rawIdent) -> AST binder sig n -> rawTerm
- convertFromScopedAST :: forall sig rawPattern rawScopedTerm rawTerm rawIdent binder (n :: S). Bifunctor sig => (sig (rawPattern, rawScopedTerm) rawTerm -> rawTerm) -> (rawIdent -> rawTerm) -> (forall (x :: S) (y :: S). binder x y -> rawPattern) -> (rawTerm -> rawScopedTerm) -> (Int -> rawIdent) -> ScopedAST binder sig n -> (rawPattern, rawScopedTerm)
- convertFromASTWith :: forall sig binder rawIdent rawTerm rawPattern rawScopedTerm (n :: S). (Bifunctor sig, Distinct n, CoSinkable binder) => (sig (rawPattern, rawScopedTerm) rawTerm -> rawTerm) -> (rawIdent -> rawTerm) -> (forall (x :: S) (y :: S). binder x y -> rawPattern) -> (rawTerm -> rawScopedTerm) -> (Name n -> rawIdent) -> (Int -> rawIdent) -> AST binder sig n -> rawTerm
- supportOf :: forall (n :: S) (binder :: S -> S -> Type) (sig :: Type -> Type -> Type). (Distinct n, CoSinkable binder, Bifoldable sig) => AST binder sig n -> NameSet n
- supportOfScopedAST :: forall (n :: S) (binder :: S -> S -> Type) (sig :: Type -> Type -> Type). (Distinct n, CoSinkable binder, Bifoldable sig) => ScopedAST binder sig n -> NameSet n
- withRelevantScope :: forall (n :: S) (binder :: S -> S -> Type) (sig :: Type -> Type -> Type) r. (Distinct n, CoSinkable binder, Bifoldable sig) => AST binder sig n -> (forall (m :: S). (Ext m n, Distinct m) => Scope m -> AST binder sig m -> r) -> r
- unsinkAST :: forall (l :: S) (binder :: S -> S -> Type) (sig :: Type -> Type -> Type) (n :: S). (Distinct l, CoSinkable binder, Bifoldable sig) => Scope n -> AST binder sig l -> Maybe (AST binder sig n)
- freeVarsOf :: forall (n :: S) (binder :: S -> S -> Type) (sig :: Type -> Type -> Type). (Distinct n, CoSinkable binder, Bifoldable sig) => AST binder sig n -> [Name n]
- freeVarsOfScopedAST :: forall (n :: S) (binder :: S -> S -> Type) (sig :: Type -> Type -> Type). (Distinct n, CoSinkable binder, Bifoldable sig) => ScopedAST binder sig n -> [Name n]
Documentation
data ScopedAST (binder :: S -> S -> Type) (sig :: Type -> Type -> Type) (n :: S) where Source #
Scoped term under a (single) name binder.
Since: 0.0.1
Constructors
| ScopedAST :: forall (binder :: S -> S -> Type) (n :: S) (l :: S) (sig :: Type -> Type -> Type). binder n l -> AST binder sig l -> ScopedAST binder sig n |
Instances
| (Bifunctor sig, CoSinkable binder, SinkableK binder) => SinkableK (ScopedAST binder sig :: S -> Type) Source # | |||||
Defined in Control.Monad.Free.Foil | |||||
| (Bifunctor sig, CoSinkable binder, SinkableK binder) => Sinkable (ScopedAST binder sig) Source # | |||||
Defined in Control.Monad.Free.Foil | |||||
| GenericK (ScopedAST binder sig :: S -> Type) Source # | |||||
Defined in Control.Monad.Free.Foil Associated Types
| |||||
| (forall (x :: S) (y :: S). Binary (binder x y), forall (l :: S). Binary (AST binder sig l)) => Binary (ScopedAST binder sig n) Source # | The binder and the body, one after the other. Decoding mints the scope under the binder. See the module documentation. | ||||
| (forall (x :: S) (y :: S). NFData (binder x y), forall (l :: S). NFData (AST binder sig l)) => NFData (ScopedAST binder sig n) Source # | |||||
Defined in Control.Monad.Free.Foil | |||||
| type RepK (ScopedAST binder sig :: S -> Type) Source # | |||||
Defined in Control.Monad.Free.Foil type RepK (ScopedAST binder sig :: S -> Type) = Exists S (Field ((('Kon binder :: Atom (S -> S -> Type) (S -> S -> Type)) ':@: (Var1 :: Atom (S -> S -> Type) S)) ':@: (Var0 :: Atom (S -> S -> Type) S)) :*: Field (((('Kon AST :: Atom (S -> S -> Type) ((S -> S -> Type) -> (Type -> Type -> Type) -> S -> Type)) ':@: ('Kon binder :: Atom (S -> S -> Type) (S -> S -> Type))) ':@: ('Kon sig :: Atom (S -> S -> Type) (Type -> Type -> Type))) ':@: (Var0 :: Atom (S -> S -> Type) S))) | |||||
data AST (binder :: S -> S -> Type) (sig :: Type -> Type -> Type) (n :: S) where Source #
A term, generated by a signature Bifunctor sig,
with (free) variables in scope n.
Since: 0.0.1
Constructors
| Var :: forall (n :: S) (binder :: S -> S -> Type) (sig :: Type -> Type -> Type). !(Name n) -> AST binder sig n | A (free) variable in scope |
| Node :: forall (sig :: Type -> Type -> Type) (binder :: S -> S -> Type) (n :: S). sig (ScopedAST binder sig n) (AST binder sig n) -> AST binder sig n | A non-variable syntactic construction specified by the signature |
Instances
| (Bifunctor sig, CoSinkable binder, SinkableK binder) => SinkableK (AST binder sig :: S -> Type) Source # | |||||
Defined in Control.Monad.Free.Foil | |||||
| (Bifunctor sig, CoSinkable binder, SinkableK binder) => RelMonad Name (AST binder sig) Source # | |||||
| Show (Expr n) Source # | Use | ||||
| (Bitraversable sig, ZipMatchK sig, UnifiablePattern binder, SinkableK binder) => AlphaEquiv (AST binder sig) Source # | A term is a scope-indexed value that can be compared up to α, which is what a pattern carrying terms as payloads needs of them. | ||||
Defined in Control.Monad.Free.Foil | |||||
| InjectName (AST binder sig) Source # | |||||
Defined in Control.Monad.Free.Foil | |||||
| (Bifunctor sig, CoSinkable binder, SinkableK binder) => Sinkable (AST binder sig) Source # | |||||
Defined in Control.Monad.Free.Foil | |||||
| GenericK (AST binder sig :: S -> Type) Source # | |||||
Defined in Control.Monad.Free.Foil Associated Types
| |||||
| (forall (x :: S) (y :: S). Binary (binder x y), forall scope term. (Binary scope, Binary term) => Binary (sig scope term)) => Binary (AST binder sig n) Source # | A tag byte, then the name or the node. | ||||
| (forall (x :: S) (y :: S). NFData (binder x y), forall scope term. (NFData scope, NFData term) => NFData (sig scope term)) => NFData (AST binder sig n) Source # | |||||
Defined in Control.Monad.Free.Foil | |||||
| Generic (AST binder sig n) Source # | |||||
Defined in Control.Monad.Free.Foil Associated Types
| |||||
| type RepK (AST binder sig :: S -> Type) Source # | |||||
Defined in Control.Monad.Free.Foil type RepK (AST binder sig :: S -> Type) = Field (Name :$: (Var0 :: Atom (S -> Type) S)) :+: Field ((sig :$: (((('Kon ScopedAST :: Atom (S -> Type) ((S -> S -> Type) -> (Type -> Type -> Type) -> S -> Type)) ':@: ('Kon binder :: Atom (S -> Type) (S -> S -> Type))) ':@: ('Kon sig :: Atom (S -> Type) (Type -> Type -> Type))) ':@: (Var0 :: Atom (S -> Type) S))) ':@: (((('Kon AST :: Atom (S -> Type) ((S -> S -> Type) -> (Type -> Type -> Type) -> S -> Type)) ':@: ('Kon binder :: Atom (S -> Type) (S -> S -> Type))) ':@: ('Kon sig :: Atom (S -> Type) (Type -> Type -> Type))) ':@: (Var0 :: Atom (S -> Type) S))) | |||||
| type Rep (AST binder sig n) Source # | |||||
Defined in Control.Monad.Free.Foil type Rep (AST binder sig n) = D1 ('MetaData "AST" "Control.Monad.Free.Foil" "free-foil-0.4.0-Bfr1HBuIt5nKrF1pl2NAYZ" 'False) (C1 ('MetaCons "Var" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'SourceUnpack 'SourceStrict 'DecidedStrict) (Rec0 (Name n))) :+: C1 ('MetaCons "Node" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (sig (ScopedAST binder sig n) (AST binder sig n))))) | |||||
Substitution
substitute :: forall (sig :: Type -> Type -> Type) (o :: S) (binder :: S -> S -> Type) (i :: S). (Bifunctor sig, Distinct o, CoSinkable binder, SinkableK binder) => Scope o -> Substitution (AST binder sig) i o -> AST binder sig i -> AST binder sig o Source #
Substitution for free (scoped monads).
Since: 0.0.1
substituteRefreshed :: forall (sig :: Type -> Type -> Type) (o :: S) (binder :: S -> S -> Type) (i :: S). (Bifunctor sig, Distinct o, CoSinkable binder, SinkableK binder) => Scope o -> Substitution (AST binder sig) i o -> AST binder sig i -> AST binder sig o Source #
Substitution for free (scoped monads).
This is a version of substitute that forces refreshing of all name binders,
resulting in a term with normalized binders:
substituteRefreshed scope subst = refreshAST scope . subtitute scope subst
In general, substitute is more efficient since it does not always refresh binders.
Since: 0.0.3
Arguments
| :: forall (sig :: Type -> Type -> Type) (o :: S) binder' (binder :: S -> S -> Type) (n :: S) (i :: S). (Bifunctor sig, Distinct o, CoSinkable binder', CoSinkable binder, SinkableK binder) | |
| => Scope o | Resulting scope. |
| -> Substitution (AST binder sig) n o | Environment mapping names in scope |
| -> binder' n i | Binders that extend scope |
| -> [AST binder sig o] | A list of terms intended to serve as |
| -> AST binder sig i | |
| -> AST binder sig o |
Substitution for a single generalized pattern.
Since: 0.2.0
\(\alpha\)-equivalence
refreshAST :: forall (sig :: Type -> Type -> Type) (n :: S) (binder :: S -> S -> Type). (Bifunctor sig, Distinct n, CoSinkable binder, SinkableK binder) => Scope n -> AST binder sig n -> AST binder sig n Source #
Refresh (force) all binders in a term, minimizing the used indices.
Since: 0.0.3
refreshScopedAST :: forall (sig :: Type -> Type -> Type) (n :: S) (binder :: S -> S -> Type). (Bifunctor sig, Distinct n, CoSinkable binder, SinkableK binder) => Scope n -> ScopedAST binder sig n -> ScopedAST binder sig n Source #
Similar to refreshAST, but for scoped terms.
Since: 0.0.3
alphaEquivRefreshed :: forall (sig :: Type -> Type -> Type) (n :: S) (binder :: S -> S -> Type). (Bitraversable sig, ZipMatchK sig, Distinct n, UnifiablePattern binder, SinkableK binder) => Scope n -> AST binder sig n -> AST binder sig n -> Bool Source #
\(\alpha\)-equivalence check for two terms in one scope
via normalization of bound identifiers (via refreshAST).
Compared to alphaEquiv, this function renames every binder on both sides
unconditionally, so it does strictly more work. It remains as an
independent implementation of the same test.
Since: 0.0.3
alphaEquiv :: forall (sig :: Type -> Type -> Type) (n :: S) (binder :: S -> S -> Type). (Bitraversable sig, ZipMatchK sig, Distinct n, UnifiablePattern binder, SinkableK binder) => Scope n -> AST binder sig n -> AST binder sig n -> Bool Source #
\(\alpha\)-equivalence check for two terms in one scope
via unification of bound variables (via unifyNameBinders).
When two matching binders coincide, comparison continues with no work at
all. When they differ, the prescribed renaming is /threaded down the
recursion/ (see alphaEquivEnv) and consulted at variables only, so
nothing is ever copied. Applying the renaming eagerly instead would
materialise a renamed copy of the remaining body at every mismatched
binder, which is quadratic on a chain of them.
Since: 0.0.3
alphaEquivScoped :: forall (sig :: Type -> Type -> Type) (binder :: S -> S -> Type) (n :: S). (Bitraversable sig, ZipMatchK sig, Distinct n, UnifiablePattern binder, SinkableK binder) => Scope n -> ScopedAST binder sig n -> ScopedAST binder sig n -> Bool Source #
Same as alphaEquiv but for scoped terms.
While the binders of the two sides coincide, this runs with no renaming
state at all. The first pair that differs switches to alphaEquivEnv,
which threads the renamings down and switches back when they empty out.
Since: 0.0.3
renamedId :: forall (n :: S) (a :: S) (b :: S). (NameBinder n a -> NameBinder n b) -> Name a -> Int Source #
The raw name a verdict's renaming assigns to a pattern's name.
Since: 0.4.0
bindPairs :: forall (sig :: Type -> Type -> Type) (binder :: S -> S -> Type) (m :: S) (l1 :: S) (l2 :: S). (Bitraversable sig, ZipMatchK sig, Distinct m, UnifiablePattern binder, SinkableK binder) => Int -> IntMap Int -> IntMap Int -> [(Int, Int)] -> Scope m -> AST binder sig l1 -> AST binder sig l2 -> Bool Source #
Bind the paired names of a binder pair. A pair whose names coincide
shadows both sides identically and is deleted from the environments. A pair
whose names differ binds both to one fresh level. Continues with
alphaEquivEnv on the bodies.
Since: 0.4.0
Arguments
| :: forall (sig :: Type -> Type -> Type) (binder :: S -> S -> Type) (n :: S) (n1 :: S) (n2 :: S). (Bitraversable sig, ZipMatchK sig, Distinct n, UnifiablePattern binder, SinkableK binder) | |
| => Int | Next fresh level. |
| -> IntMap Int | Left renaming: raw name to the level that bound it. |
| -> IntMap Int | Right renaming. |
| -> Scope n | Scope along the unified path (consulted by |
| -> AST binder sig n1 | |
| -> AST binder sig n2 | |
| -> Bool |
The renaming-threading worker behind alphaEquiv: compare two terms
under partial renamings of their names into shared levels.
Each environment maps a raw name to the level of the binder pair that bound it on the comparison path, and a name outside its environment stands for itself. A variable occurrence then compares as a level against a level, or as a raw name against a raw name, and the two can never be conflated. This is what makes threading sound where applying a raw renaming at the variables would not be, since a renamed name could collide with one that passes through unchanged and happens to share the target spelling. Levels are also why no capture check is needed: a level is never a name, so there is nothing for a binder to capture.
A binder pair whose names coincide deletes those names from both
environments, the pair shadowing both sides identically. When the
environments empty out the comparison drops back to the stateless
alphaEquiv, so only the region of the terms below a mismatched binder,
and above the point where the mismatch is shadowed away, pays for the
threading at all.
The indices of the two terms are deliberately independent, in the style
of unsafeEqAST: the terms are never renamed into a common scope, so
no common index exists to give them.
Since: 0.4.0
alphaEquivScopedEnv :: forall (sig :: Type -> Type -> Type) (binder :: S -> S -> Type) (n :: S) (n1 :: S) (n2 :: S). (Bitraversable sig, ZipMatchK sig, Distinct n, UnifiablePattern binder, SinkableK binder) => Int -> IntMap Int -> IntMap Int -> Scope n -> ScopedAST binder sig n1 -> ScopedAST binder sig n2 -> Bool Source #
The scoped half of alphaEquivEnv: get the verdict from
unifyPatternsIn, extend the environments as it prescribes, and
recurse into the bodies as they stand.
Since: 0.4.0
Unsafe equality checks
unsafeEqAST :: forall (sig :: Type -> Type -> Type) (binder :: S -> S -> Type) (n :: S) (l :: S). (Bitraversable sig, ZipMatchK sig, UnifiablePattern binder, Distinct n, Distinct l) => AST binder sig n -> AST binder sig l -> Bool Source #
Unsafe equality check for two terms. This check ignores the possibility that two terms might have different scope extensions under binders (which might happen due to substitution under a binder in absence of name conflicts).
Since: 0.0.3
unsafeEqScopedAST :: forall (sig :: Type -> Type -> Type) (binder :: S -> S -> Type) (n :: S) (l :: S). (Bitraversable sig, ZipMatchK sig, UnifiablePattern binder, Distinct n, Distinct l) => ScopedAST binder sig n -> ScopedAST binder sig l -> Bool Source #
A version of unsafeEqAST for scoped terms.
Since: 0.0.3
Converting to and from free foil
Convert to free foil
data UnresolvedName rawIdent Source #
An identifier a raw term mentions that the names given for conversion do not account for.
Note what this does and does not carry. It cannot carry a position: the
conversion functions are generic in the raw term and only ever see it through
toSig, so a source location, if the syntax has one, is not theirs to read.
What they do know, and a caller checking names beforehand does not, is which
names were in scope at the occurrence, the binders passed on the way down
included. That is what a "did you mean" needs.
Since: 0.4.0
Constructors
| UnresolvedName | |
Fields
| |
Instances
Arguments
| :: forall sig binder rawIdent rawTerm rawPattern rawScopedTerm (n :: S). (Distinct n, Bifoldable sig, Ord rawIdent, CoSinkable binder) | |
| => (rawTerm -> Either rawIdent (sig (rawPattern, rawScopedTerm) rawTerm)) | Unpeel one syntax node (or a variable) from a raw term. |
| -> (forall (x :: S) z. Distinct x => Scope x -> Map rawIdent (Name x) -> rawPattern -> (forall (y :: S). DExt x y => binder x y -> Map rawIdent (Name y) -> z) -> z) | Convert raw pattern into a scope-safe pattern. |
| -> (rawScopedTerm -> rawTerm) | Extract a term from a scoped term (or crash). |
| -> Scope n | Resulting scope of the constructed term. |
| -> Map rawIdent (Name n) | Known names of free variables in scope |
| -> rawTerm | Raw term. |
| -> [UnresolvedName rawIdent] |
The identifiers a raw term mentions that a set of names cannot resolve, in the order they occur.
This is unsafeConvertToAST with the conversion left out, so it descends
under binders in the same way and accounts for what they bind.
Since: 0.4.0
Arguments
| :: forall sig binder rawIdent rawTerm rawPattern rawScopedTerm (n :: S). (Distinct n, Bitraversable sig, Ord rawIdent, CoSinkable binder, SinkableK binder) | |
| => (rawTerm -> Either rawIdent (sig (rawPattern, rawScopedTerm) rawTerm)) | Unpeel one syntax node (or a variable) from a raw term. |
| -> (forall (x :: S) z. Distinct x => Scope x -> Map rawIdent (Name x) -> rawPattern -> (forall (y :: S). DExt x y => binder x y -> Map rawIdent (Name y) -> z) -> z) | Convert raw pattern into a scope-safe pattern. |
| -> (rawScopedTerm -> rawTerm) | Extract a term from a scoped term (or crash). |
| -> Scope n | Resulting scope of the constructed term. |
| -> Map rawIdent (Name n) | Known names of free variables in scope |
| -> rawTerm | Raw term. |
| -> Either (UnresolvedName rawIdent) (AST binder sig n) |
Convert a raw term into a scope-safe term, reporting the first identifier that does not resolve.
One pass, short-circuiting at the first failure, so a term that resolves
costs no more than unsafeConvertToAST does. The report is complete for
that one identifier, since unresolvedInScope is built where the conversion
fails and is never computed on the way through.
A caller wanting every unresolved identifier rather than the first pays a
second pass for it, with unresolvedNames. The successful path stays fast
that way, and a failure can afford to be walked again for a better message.
Since: 0.4.0
Arguments
| :: forall sig binder rawIdent rawTerm rawPattern rawScopedTerm (n :: S). (Distinct n, Bitraversable sig, Ord rawIdent, CoSinkable binder, SinkableK binder) | |
| => (rawTerm -> Either rawIdent (sig (rawPattern, rawScopedTerm) rawTerm)) | Unpeel one syntax node (or a variable) from a raw term. |
| -> (forall (x :: S) z. Distinct x => Scope x -> Map rawIdent (Name x) -> rawPattern -> (forall (y :: S). DExt x y => binder x y -> Map rawIdent (Name y) -> z) -> z) | Convert raw pattern into a scope-safe pattern. |
| -> (rawScopedTerm -> rawTerm) | Extract a term from a scoped term (or crash). |
| -> Scope n | Resulting scope of the constructed term. |
| -> Map rawIdent (Name n) | Known names of free variables in scope |
| -> Map rawIdent (AST binder sig n) | Identifiers that denote a term rather than a variable. |
| -> rawTerm | Raw term. |
| -> Either (UnresolvedName rawIdent) (AST binder sig n) |
Convert a raw term into a scope-safe term, resolving some identifiers to whole terms rather than to variables.
The extra table is what a language with constants needs: an identifier that denotes a top-level declaration, a primitive, or an abbreviation stands for something that is not a variable, and resolving it during conversion is the only place where the binders are known. Doing it in a pass of one's own means writing a binder-aware traversal of the raw syntax by hand.
Variables win: the table of names is consulted first, so a binder shadows an entry here, and an entry here shadows nothing. The table is sunk when going under a binder, exactly as the names are, so its entries may mention anything in scope where conversion started and need not be closed.
Since: 0.4.0
Arguments
| :: forall (n :: S) sig rawIdent binder rawTerm rawPattern rawScopedTerm. (Distinct n, Bifunctor sig, Ord rawIdent, CoSinkable binder) | |
| => (rawTerm -> Either rawIdent (sig (rawPattern, rawScopedTerm) rawTerm)) | Unpeel one syntax node (or a variable) from a raw term. |
| -> (forall (x :: S) z. Distinct x => Scope x -> Map rawIdent (Name x) -> rawPattern -> (forall (y :: S). DExt x y => binder x y -> Map rawIdent (Name y) -> z) -> z) | Convert raw pattern into a scope-safe pattern. |
| -> (rawScopedTerm -> rawTerm) | Extract a term from a scoped term (or crash). |
| -> Scope n | Resulting scope of the constructed term. |
| -> Map rawIdent (Name n) | Known names of free variables in scope |
| -> rawTerm | Raw term. |
| -> AST binder sig n |
Convert a raw term into a scope-safe term, calling error on an
identifier that does not resolve.
Prefer tryConvertToAST, which reports such identifiers. This is for callers
that have already established that every name resolves.
Since: 0.4.0
unsafeConvertToScopedAST Source #
Arguments
| :: forall (n :: S) sig rawIdent binder rawTerm rawPattern rawScopedTerm. (Distinct n, Bifunctor sig, Ord rawIdent, CoSinkable binder) | |
| => (rawTerm -> Either rawIdent (sig (rawPattern, rawScopedTerm) rawTerm)) | Unpeel one syntax node (or a variable) from a raw term. |
| -> (forall (x :: S) z. Distinct x => Scope x -> Map rawIdent (Name x) -> rawPattern -> (forall (y :: S). DExt x y => binder x y -> Map rawIdent (Name y) -> z) -> z) | Convert raw pattern into a scope-safe pattern. |
| -> (rawScopedTerm -> rawTerm) | Extract a term from a scoped term (or crash). |
| -> Scope n | Resulting scope of the constructed term. |
| -> Map rawIdent (Name n) | Known names of free variables in scope |
| -> (rawPattern, rawScopedTerm) | A pair of a pattern and a corresponding scoped term. |
| -> ScopedAST binder sig n |
Same as unsafeConvertToAST but for scoped terms.
Since: 0.4.0
convertToAST :: forall (n :: S) sig rawIdent binder rawTerm rawPattern rawScopedTerm. (Distinct n, Bifunctor sig, Ord rawIdent, CoSinkable binder) => (rawTerm -> Either rawIdent (sig (rawPattern, rawScopedTerm) rawTerm)) -> (forall (x :: S) z. Distinct x => Scope x -> Map rawIdent (Name x) -> rawPattern -> (forall (y :: S). DExt x y => binder x y -> Map rawIdent (Name y) -> z) -> z) -> (rawScopedTerm -> rawTerm) -> Scope n -> Map rawIdent (Name n) -> rawTerm -> AST binder sig n Source #
Deprecated: Renamed to unsafeConvertToAST, since it calls error on an unresolved identifier. Use tryConvertToAST to report them instead.
Convert a raw term into a scope-safe term.
Since: 0.0.3
convertToScopedAST :: forall (n :: S) sig rawIdent binder rawTerm rawPattern rawScopedTerm. (Distinct n, Bifunctor sig, Ord rawIdent, CoSinkable binder) => (rawTerm -> Either rawIdent (sig (rawPattern, rawScopedTerm) rawTerm)) -> (forall (x :: S) z. Distinct x => Scope x -> Map rawIdent (Name x) -> rawPattern -> (forall (y :: S). DExt x y => binder x y -> Map rawIdent (Name y) -> z) -> z) -> (rawScopedTerm -> rawTerm) -> Scope n -> Map rawIdent (Name n) -> (rawPattern, rawScopedTerm) -> ScopedAST binder sig n Source #
Deprecated: Renamed to unsafeConvertToScopedAST, since it calls error on an unresolved identifier.
Same as convertToAST but for scoped terms.
Since: 0.0.3
Convert from free foil
Arguments
| :: forall sig rawPattern rawScopedTerm rawTerm rawIdent binder (n :: S). Bifunctor sig | |
| => (sig (rawPattern, rawScopedTerm) rawTerm -> rawTerm) | Peel back one layer of syntax. |
| -> (rawIdent -> rawTerm) | Convert identifier into a raw variable term. |
| -> (forall (x :: S) (y :: S). binder x y -> rawPattern) | Convert scope-safe pattern into a raw pattern. |
| -> (rawTerm -> rawScopedTerm) | Wrap raw term into a scoped term. |
| -> (Int -> rawIdent) | Convert underlying integer identifier of a bound variable into a raw identifier. |
| -> AST binder sig n | Scope-safe term. |
| -> rawTerm |
Convert a scope-safe term back into a raw term.
Since: 0.0.3
Arguments
| :: forall sig rawPattern rawScopedTerm rawTerm rawIdent binder (n :: S). Bifunctor sig | |
| => (sig (rawPattern, rawScopedTerm) rawTerm -> rawTerm) | Peel back one layer of syntax. |
| -> (rawIdent -> rawTerm) | Convert identifier into a raw variable term. |
| -> (forall (x :: S) (y :: S). binder x y -> rawPattern) | Convert scope-safe pattern into a raw pattern. |
| -> (rawTerm -> rawScopedTerm) | Wrap raw term into a scoped term. |
| -> (Int -> rawIdent) | Convert underlying integer identifier of a bound variable into a raw identifier. |
| -> ScopedAST binder sig n | Scope-safe scoped term. |
| -> (rawPattern, rawScopedTerm) |
Same as convertFromAST but for scoped terms.
Since: 0.0.3
Arguments
| :: forall sig binder rawIdent rawTerm rawPattern rawScopedTerm (n :: S). (Bifunctor sig, Distinct n, CoSinkable binder) | |
| => (sig (rawPattern, rawScopedTerm) rawTerm -> rawTerm) | Peel back one layer of syntax. |
| -> (rawIdent -> rawTerm) | Convert identifier into a raw variable term. |
| -> (forall (x :: S) (y :: S). binder x y -> rawPattern) | Convert scope-safe pattern into a raw pattern. |
| -> (rawTerm -> rawScopedTerm) | Wrap raw term into a scoped term. |
| -> (Name n -> rawIdent) | Name a variable that is free in the whole term. |
| -> (Int -> rawIdent) | Name a bound variable, from its underlying integer identifier. |
| -> AST binder sig n | Scope-safe term. |
| -> rawTerm |
Convert a scope-safe term back into a raw term, naming the variables that occur free in the whole term separately from the bound ones.
convertFromAST applies one naming function to every variable it meets,
bound or free, and gives it only a raw name. That is often not enough, since
raw names are not unique across scope indices: a binder inside a term may
share one with a name of the ambient scope, so naming by raw name alone can
print a bound variable as whatever the ambient scope calls that name.
Keeping the typed name is what distinguishes them, and unsinkNamePattern
is the operation for it: composing one per binder on the way down builds a
that answers exactly the question.Name x -> Maybe (Name n)
Since: 0.4.0
Unsinking AST
supportOf :: forall (n :: S) (binder :: S -> S -> Type) (sig :: Type -> Type -> Type). (Distinct n, CoSinkable binder, Bifoldable sig) => AST binder sig n -> NameSet n Source #
The support of a term: exactly the names that occur free in it.
This is the annotation that co-de-Bruijn syntax carries intrinsically and that the foil, having global names and therefore free weakening, does not. Computing it is \(O(size)\); a client that restricts often should cache it.
Since: 0.4.0
supportOfScopedAST :: forall (n :: S) (binder :: S -> S -> Type) (sig :: Type -> Type -> Type). (Distinct n, CoSinkable binder, Bifoldable sig) => ScopedAST binder sig n -> NameSet n Source #
The support of a scoped term, in the scope outside its binder.
Since: 0.4.0
withRelevantScope :: forall (n :: S) (binder :: S -> S -> Type) (sig :: Type -> Type -> Type) r. (Distinct n, CoSinkable binder, Bifoldable sig) => AST binder sig n -> (forall (m :: S). (Ext m n, Distinct m) => Scope m -> AST binder sig m -> r) -> r Source #
Cut a term down to the scope of exactly the names it uses.
This is the a-priori form of restriction, and the cheap one: the term
inhabits the smaller scope by construction, so nothing is tested and
nothing can fail. comes back with it, so the term can be
Ext m nsinked to where it came from for free.
Verifying a declared dependency, such as a uses clause or a module's
parameters, is this plus a comparison: compute the scope a term really
inhabits, and check the declared one against it.
Since: 0.4.0
unsinkAST :: forall (l :: S) (binder :: S -> S -> Type) (sig :: Type -> Type -> Type) (n :: S). (Distinct l, CoSinkable binder, Bifoldable sig) => Scope n -> AST binder sig l -> Maybe (AST binder sig n) Source #
Unsink an AST from a larger scope to a smaller scope.
This is the a-posteriori form, and the one that has to be paid for: the term's support is computed and compared against the scope. When it succeeds the term itself is untouched, since restriction of a term that does inhabit the smaller scope is a coercion.
Since: 0.3.0
freeVarsOf :: forall (n :: S) (binder :: S -> S -> Type) (sig :: Type -> Type -> Type). (Distinct n, CoSinkable binder, Bifoldable sig) => AST binder sig n -> [Name n] Source #
Get the free variables of an AST.
These come from supportOf, so they are distinct and in ascending order of
their identifiers.
Since: 0.3.0
freeVarsOfScopedAST :: forall (n :: S) (binder :: S -> S -> Type) (sig :: Type -> Type -> Type). (Distinct n, CoSinkable binder, Bifoldable sig) => ScopedAST binder sig n -> [Name n] Source #
Get the free variables of a scoped AST, in the scope outside its binder.
Since: 0.3.0