Safe Haskell | None |
---|---|
Language | Haskell2010 |
Foil implementation of the \(\lambda\Pi\)-calculus (with pairs).
The following is implemented manually in this module:
- Scope-safe AST for \(\lambda\Pi\)-terms.
- Correct capture-avoiding substitution (see
substitute
). - Conversion between scope-safe and raw term representation (the latter is generated via BNFC), see
toFoilTerm
andfromFoilTerm
. - Helper functions for patterns. See
extendScopePattern
andwithRefreshedPattern
. - \(\alpha\)-equivalence checks (
alphaEquiv
andalphaEquivRefreshed
) and \(\alpha\)-normalization helpers (refreshExpr
). - Computation of weak head normal form (WHNF) and normal form (NF), see
whnf
andnf
. - Entry point, gluing everything together. See
defaultMain
.
This implementation supports (nested) patterns for pairs.
This is a baseline implementation, see other examples for partial automation:
- Language.LambdaPi.Impl.FreeFoil allows to reuse generalized substitution and \(\alpha\)-equivalence (and, in theory, more complicated algorithms).
- Language.LambdaPi.Impl.FoilTH works well with patterns and generates conversion functions and helpers for patterns.
- Language.LambdaPi.Impl.FreeFoilTH combines the benefits of the above, when it is possible to generate the signature automatically.
Synopsis
- data Expr (n :: S) where
- VarE :: forall (n :: S). Name n -> Expr n
- AppE :: forall (n :: S). Expr n -> Expr n -> Expr n
- LamE :: forall (n :: S) (l :: S). Pattern n l -> Expr l -> Expr n
- PiE :: forall (n :: S) (l :: S). Pattern n l -> Expr n -> Expr l -> Expr n
- PairE :: forall (n :: S). Expr n -> Expr n -> Expr n
- FirstE :: forall (n :: S). Expr n -> Expr n
- SecondE :: forall (n :: S). Expr n -> Expr n
- ProductE :: forall (n :: S). Expr n -> Expr n -> Expr n
- UniverseE :: forall (n :: S). Expr n
- data Pattern (n :: S) (l :: S) where
- PatternWildcard :: forall (n :: S). Pattern n n
- PatternVar :: forall (n :: S) (l :: S). NameBinder n l -> Pattern n l
- PatternPair :: forall (n :: S) (i :: S) (l :: S). Pattern n i -> Pattern i l -> Pattern n l
- ppName :: forall (n :: S). Name n -> String
- ppExpr :: forall (n :: S). Expr n -> String
- ppPattern :: forall (n :: S) (l :: S). Pattern n l -> String
- printExpr :: Expr 'VoidS -> String
- substitute :: forall (o :: S) (i :: S). Distinct o => Scope o -> Substitution Expr i o -> Expr i -> Expr o
- substituteRefresh :: forall (o :: S) (i :: S). Distinct o => Scope o -> Substitution Expr i o -> Expr i -> Expr o
- toFoilPattern :: forall (n :: S) r. Distinct n => Scope n -> Map VarIdent (Name n) -> Pattern -> (forall (l :: S). DExt n l => Pattern n l -> Map VarIdent (Name l) -> r) -> r
- toFoilTerm :: forall (n :: S). Distinct n => Scope n -> Map VarIdent (Name n) -> Term -> Expr n
- toFoilTermClosed :: Term -> Expr 'VoidS
- fromFoilPattern :: forall (n :: S) (l :: S) r. [VarIdent] -> NameMap n VarIdent -> Pattern n l -> ([VarIdent] -> NameMap l VarIdent -> Pattern -> r) -> r
- fromFoilTerm :: forall (n :: S). [VarIdent] -> NameMap n VarIdent -> Expr n -> Term
- fromFoilTermClosed :: [VarIdent] -> Expr 'VoidS -> Term
- fromFoilPattern' :: forall (n :: S) (l :: S). Pattern n l -> Pattern
- fromFoilTerm' :: forall (n :: S). Expr n -> Term
- matchPattern :: forall (n :: S) (l :: S). Pattern n l -> Expr n -> Substitution Expr l n
- whnf :: forall (n :: S). Distinct n => Scope n -> Expr n -> Expr n
- refreshExpr :: forall (n :: S). Distinct n => Scope n -> Expr n -> Expr n
- alphaEquivRefreshed :: forall (n :: S). Distinct n => Scope n -> Expr n -> Expr n -> Bool
- unsafeEqPattern :: forall (n :: S) (l :: S) (n' :: S) (l' :: S). Pattern n l -> Pattern n' l' -> Bool
- unsafeEqExpr :: forall (n :: S) (l :: S). Expr n -> Expr l -> Bool
- alphaEquiv :: forall (n :: S). Distinct n => Scope n -> Expr n -> Expr n -> Bool
- interpretCommand :: Command -> IO ()
- interpretProgram :: Program -> IO ()
- defaultMain :: IO ()
- lam :: forall (n :: S). Distinct n => Scope n -> (forall (l :: S). DExt n l => Scope l -> NameBinder n l -> Expr l) -> Expr n
- identity :: Expr 'VoidS
- churchN :: Int -> Expr 'VoidS
Documentation
>>>
:set -XOverloadedStrings
>>>
:set -XDataKinds
>>>
import Control.Monad.Foil
Scope-safe AST
data Expr (n :: S) where Source #
Type of scope-safe \(\lambda\Pi\)-terms with pairs.
VarE :: forall (n :: S). Name n -> Expr n | Variables: \(x\) |
AppE :: forall (n :: S). Expr n -> Expr n -> Expr n | Application: \((t_1 \; t_2)\) |
LamE :: forall (n :: S) (l :: S). Pattern n l -> Expr l -> Expr n | Abstraction (with patterns): \(\lambda p. t\) |
PiE :: forall (n :: S) (l :: S). Pattern n l -> Expr n -> Expr l -> Expr n | \(\prod\)-types (with patterns): \(\prod_{p : T_1} T_2\) |
PairE :: forall (n :: S). Expr n -> Expr n -> Expr n | Pair of terms: \(\langle t_1, t_2 \rangle\) |
FirstE :: forall (n :: S). Expr n -> Expr n | First projection: \(\pi_1(t)\) |
SecondE :: forall (n :: S). Expr n -> Expr n | Second projection: \(\pi_2(t)\) |
ProductE :: forall (n :: S). Expr n -> Expr n -> Expr n | Product type (non-dependent): \(T_1 \times T_2\) |
UniverseE :: forall (n :: S). Expr n | Universe (type of types): \(\mathcal{U}\) |
Instances
InjectName Expr Source # | |
Defined in Language.LambdaPi.Impl.Foil injectName :: forall (n :: S). Name n -> Expr n # | |
Sinkable Expr Source # | |
Defined in Language.LambdaPi.Impl.Foil | |
RelMonad Name Expr Source # | |
IsString (Expr 'VoidS) Source # | |
Defined in Language.LambdaPi.Impl.Foil fromString :: String -> Expr 'VoidS # | |
Show (Expr 'VoidS) Source # | |
data Pattern (n :: S) (l :: S) where Source #
Patterns.
PatternWildcard :: forall (n :: S). Pattern n n | Wildcard pattern: \(_\) |
PatternVar :: forall (n :: S) (l :: S). NameBinder n l -> Pattern n l | Variable pattern: \(x\) |
PatternPair :: forall (n :: S) (i :: S) (l :: S). Pattern n i -> Pattern i l -> Pattern n l | Pair pattern: \((p_1, p_2)\) |
Instances
CoSinkable Pattern Source # | |
Defined in Language.LambdaPi.Impl.Foil coSinkabilityProof :: forall (n :: S) (n' :: S) (l :: S) r. (Name n -> Name n') -> Pattern n l -> (forall (l' :: S). (Name l -> Name l') -> Pattern n' l' -> r) -> r # withPattern :: forall (o :: S) f (n :: S) (l :: S) r. Distinct o => (forall (x :: S) (y :: S) (z :: S) r'. Distinct z => Scope z -> NameBinder x y -> (forall (z' :: S). DExt z z' => f x y z z' -> NameBinder z z' -> r') -> r') -> (forall (x :: S) (z :: S) (z' :: S). DExt z z' => f x x z z') -> (forall (x :: S) (y :: S) (y' :: S) (z :: S) (z' :: S) (z'' :: S). (DExt z z', DExt z' z'') => f x y z z' -> f y y' z' z'' -> f x y' z z'') -> Scope o -> Pattern n l -> (forall (o' :: S). DExt o o' => f n l o o' -> Pattern o o' -> r) -> r # | |
UnifiablePattern Pattern Source # | |
Defined in Language.LambdaPi.Impl.Foil unifyPatterns :: forall (n :: S) (l :: S) (r :: S). Distinct n => Pattern n l -> Pattern n r -> UnifyNameBinders Pattern n l r # |
Pretty-printing
ppName :: forall (n :: S). Name n -> String Source #
Default way to print a name using its internal Id
.
ppExpr :: forall (n :: S). Expr n -> String Source #
Pretty-print a \(\lambda\Pi\)-term directly (without converting to raw term).
>>>
ppExpr identity
"\955x0. x0">>>
ppExpr (churchN 2)
"\955x0. \955x1. x0 (x0 (x1))"
ppPattern :: forall (n :: S) (l :: S). Pattern n l -> String Source #
Pretty-print a pattern in a \(\lambda\Pi\)-term (without converting to raw pattern)..
printExpr :: Expr 'VoidS -> String Source #
Pretty-print a closed scode-safe \(\lambda\Pi\)-term
using BNFC-generated printer (via Term
).
Substitution
substitute :: forall (o :: S) (i :: S). Distinct o => Scope o -> Substitution Expr i o -> Expr i -> Expr o Source #
Perform substitution in a \(\lambda\Pi\)-term.
substituteRefresh :: forall (o :: S) (i :: S). Distinct o => Scope o -> Substitution Expr i o -> Expr i -> Expr o Source #
Perform substitution in a \(\lambda\Pi\)-term and normalize binders in the process.
Conversion
From raw to foil
:: forall (n :: S) r. Distinct n | |
=> Scope n | Outer scope (outside of pattern binding). |
-> Map VarIdent (Name n) | Mapping for variable names (to be extended with pattern). |
-> Pattern | Raw pattern. |
-> (forall (l :: S). DExt n l => Pattern n l -> Map VarIdent (Name l) -> r) | A continuation, accepting a scope-safe pattern and an updated variable mapping. |
-> r |
Convert a raw pattern into a scope-safe one.
:: forall (n :: S). Distinct n | |
=> Scope n | Target scope. |
-> Map VarIdent (Name n) | Mapping for variable names (to be extended with pattern). |
-> Term | A raw term. |
-> Expr n |
Convert a raw term into a scope-safe \(\lambda\Pi\)-term.
From foil to raw
:: forall (n :: S) (l :: S) r. [VarIdent] | A stream of fresh variable identifiers. |
-> NameMap n VarIdent | A total mapping for names in scope |
-> Pattern n l | A scope-safe pattern that extends scope |
-> ([VarIdent] -> NameMap l VarIdent -> Pattern -> r) | A continutation, accepting (smaller) stream of fresh variable identifiers, a mapping for the inner scope, and a raw pattern. |
-> r |
Convert a scope-safe pattern into a raw pattern.
:: forall (n :: S). [VarIdent] | A stream of fresh variable identifiers. |
-> NameMap n VarIdent | A total mapping for names in scope |
-> Expr n | A scope safe term in scope |
-> Term |
Convert a scope-safe term into a raw term.
:: [VarIdent] | A stream of fresh variable identifiers. |
-> Expr 'VoidS | A scope safe term in scope |
-> Term |
Convert a closed scope-safe term into a raw term.
:: forall (n :: S) (l :: S). Pattern n l | A scope-safe pattern that extends scope |
-> Pattern |
Convert a scope-safe pattern into a raw pattern converting raw
identifiers directly into VarIdent
Convert a scope-safe term into a raw term converting raw
identifiers directly into VarIdent
.
Evaluation
matchPattern :: forall (n :: S) (l :: S). Pattern n l -> Expr n -> Substitution Expr l n Source #
Match a pattern against an expression.
whnf :: forall (n :: S). Distinct n => Scope n -> Expr n -> Expr n Source #
Compute weak head normal form (WHNF).
>>>
whnf emptyScope "(λx.(λ_.x)(λy.x))(λy.λz.z)"
λ x0 . λ x1 . x1
>>>
whnf emptyScope "(λs.λz.s(s(z)))(λs.λz.s(s(z)))"
λ x1 . (λ x0 . λ x1 . x0 (x0 x1)) ((λ x0 . λ x1 . x0 (x0 x1)) x1)
Note that during computation bound variables can become unordered in the sense that binders may easily repeat or decrease. For example, in the following expression, inner binder has lower index that the outer one:
>>>
whnf emptyScope "(λx.λy.x)(λx.x)"
λ x1 . λ x0 . x0
At the same time, without substitution, we get regular, increasing binder indices:
>>>
"λx.λy.y" :: Expr VoidS
λ x0 . λ x1 . x1
To compare terms for \(\alpha\)-equivalence, we may use alphaEquiv
:
>>>
alphaEquiv emptyScope (whnf emptyScope "(λx.λy.x)(λx.x)") "λx.λy.y"
True
We may also normalize binders using refreshExpr
:
>>>
refreshExpr emptyScope (whnf emptyScope "(λx.λy.x)(λx.x)")
λ x0 . λ x1 . x1
\(\alpha\)-equivalence
refreshExpr :: forall (n :: S). Distinct n => Scope n -> Expr n -> Expr n Source #
Normalize all binder identifiers in an expression.
alphaEquivRefreshed :: forall (n :: S). Distinct n => Scope n -> Expr n -> Expr n -> Bool Source #
\(\alpha\)-equivalence check for two terms in one scope
via normalization of bound identifiers (via refreshExpr
).
This function may perform some unnecessary changes of bound variables when the binders are the same on both sides.
unsafeEqPattern :: forall (n :: S) (l :: S) (n' :: S) (l' :: S). Pattern n l -> Pattern n' l' -> Bool Source #
Unsafely check for equality of two Pattern
s.
This does not include \(\alpha\)-equivalence!
unsafeEqExpr :: forall (n :: S) (l :: S). Expr n -> Expr l -> Bool Source #
Unsafely check for equality of two Expr
s.
This does not include \(\alpha\)-equivalence!
alphaEquiv :: forall (n :: S). Distinct n => Scope n -> Expr n -> Expr n -> Bool Source #
\(\alpha\)-equivalence check for two terms in one scope
via unification of bound variables (via unifyNameBinders
).
Compared to alphaEquivRefreshed
, this function might skip unnecessary
changes of bound variables when both binders in two matching scoped terms coincide.
Interpreter
interpretCommand :: Command -> IO () Source #
Interpret a \(\lambda\Pi\) command.
interpretProgram :: Program -> IO () Source #
Interpret a \(\lambda\Pi\) program.
defaultMain :: IO () Source #
Default interpreter program. Reads a \(\lambda\Pi\) program from the standard input and runs the commands.