Four design challenges
- Substitution vs let-bindings
- Typed vs untyped conversion
- Checking vs inferring case expressions
- Minimal vs invariant-rich syntax
1. Substitution vs let
We define reduction using an abstract machine:
- An environment of shared terms
- A focus term currently being evaluated
- A stack of frames to continue evaluating later
1. Substitution vs let
Ways to convert a machine state back into a term:
- Substitution: duplicates terms! (*)
let
-bindings: retains unused
terms!
- Retaining the environment everywhere?
2. Typed vs untyped conversion
Agda uses typed conversion for a few features:
- Eta-equality for functions
- Eta-equality for record types
- In particular: eta-equality for the unit type
- Definitional proof irrelevant
Prop
universe
2. Typed vs untyped conversion
2. Typed vs untyped conversion
How can we allow for comparing types at different sorts (e.g. domain
of pi type)?
- A typed conversion judgement
- always need to compare sorts of types first
- An untyped conversion judgement
- do eta-expansion in the elaborator?
- do eta-expansion in the conversion checker? (*)
- Two conversion judgements: a typed one for terms and an untyped one
for types
3. Checking vs inferring case expressions
In Agda Core, pattern matching is represented as an
elimination:
We’d like to use case
without typing annotations, but
that does not fit cleanly in a bidirectional discipline!
3. Checking vs inferring case expressions
Possible solutions:
- Require a type annotation on each
case
(*)
- Model only definition-level pattern matching
- Only allow case on a variable
4. Minimal vs invariant-rich syntax
Data/record types are represented with as a Def
, so
checking a constructor application requires:
- checking if the given type is a datatype
- extracting its parameters and indices
4. Minimal vs invariant-rich syntax
4. Minimal vs invariant-rich syntax
This would be much cleaner with a dedicated syntax constructor for
datatypes!
Is simplifying the type checker worth adding extra complexity to the
syntax?