608 lines
22 KiB
Racket
608 lines
22 KiB
Racket
#lang racket/base
|
||
|
||
;; A mostly Redex core, with parts written in Racket for performance reasons
|
||
;; TODO: Move tests into common place to use in both Redex cores.
|
||
|
||
(require
|
||
racket/dict
|
||
racket/function
|
||
redex/reduction-semantics)
|
||
|
||
(provide
|
||
(all-defined-out))
|
||
|
||
(set-cache-size! 10000)
|
||
|
||
;; Test suite setup.
|
||
(module+ test
|
||
(require
|
||
rackunit
|
||
(only-in racket/set set=?))
|
||
(define-syntax-rule (check-holds (e ...))
|
||
(check-true
|
||
(judgment-holds (e ...))))
|
||
(define-syntax-rule (check-not-holds (e ...))
|
||
(check-false
|
||
(judgment-holds (e ...))))
|
||
(define-syntax-rule (check-equiv? e1 e2)
|
||
(check (default-equiv) e1 e2))
|
||
(define-syntax-rule (check-not-equiv? e1 e2)
|
||
(check (compose not (default-equiv)) e1 e2)))
|
||
|
||
#| ttL is the core language of Cur. Very similar to TT (Idirs core) and Luo's UTT. Surface
|
||
| langauge should provide short-hand, such as -> for non-dependent function types, and type
|
||
| inference.
|
||
|#
|
||
(define-language ttL
|
||
(i j k ::= natural)
|
||
(U ::= (Unv i))
|
||
(t e ::= U (λ (x : t) e) x (Π (x : t) t) (e e) (elim D U))
|
||
;; Δ (signature). (inductive-name : type ((constructor : type) ...))
|
||
;; NB: Δ is a map from a name x to a pair of it's type and a map of constructor names to their types
|
||
(Δ ::= ∅ (Δ (D : t ((c : t) ...))))
|
||
(D x c ::= variable-not-otherwise-mentioned)
|
||
#:binding-forms
|
||
(λ (x : t) e #:refers-to x)
|
||
(Π (x : t_0) t_1 #:refers-to x))
|
||
|
||
(define x? (redex-match? ttL x))
|
||
(define t? (redex-match? ttL t))
|
||
(define e? (redex-match? ttL e))
|
||
(define U? (redex-match? ttL U))
|
||
(define Δ? (redex-match? ttL Δ))
|
||
|
||
;;; ------------------------------------------------------------------------
|
||
;;; Universe typing
|
||
|
||
(define-judgment-form ttL
|
||
#:mode (unv-type I O)
|
||
#:contract (unv-type U U)
|
||
|
||
[(where i_1 ,(add1 (term i_0)))
|
||
-----------------
|
||
(unv-type (Unv i_0) (Unv i_1))])
|
||
|
||
;; Universe predicativity rules. Impredicative in (Unv 0)
|
||
(define-judgment-form ttL
|
||
#:mode (unv-pred I I O)
|
||
#:contract (unv-pred U U U)
|
||
|
||
[----------------
|
||
(unv-pred (Unv i) (Unv 0) (Unv 0))]
|
||
|
||
[(where i_3 ,(max (term i_1) (term i_2)))
|
||
----------------
|
||
(unv-pred (Unv i_1) (Unv i_2) (Unv i_3))])
|
||
|
||
(define-metafunction ttL
|
||
α-equivalent? : t t -> #t or #f
|
||
[(α-equivalent? t_0 t_1)
|
||
,(alpha-equivalent? ttL (term t_0) (term t_1))])
|
||
|
||
;; Replace x by t_1 in t_0
|
||
(define-metafunction ttL
|
||
subst : t x t -> t
|
||
[(subst t_0 x t_1)
|
||
(substitute t_0 x t_1)])
|
||
|
||
(define-metafunction ttL
|
||
subst-all : t (x ...) (e ...) -> t
|
||
[(subst-all t () ()) t]
|
||
[(subst-all t (x_0 x ...) (e_0 e ...))
|
||
(subst-all (subst t x_0 e_0) (x ...) (e ...))])
|
||
|
||
;;; ------------------------------------------------------------------------
|
||
;;; Primitive Operations on signatures Δ (those operations that do not require contexts)
|
||
|
||
;;; TODO: Might be worth maintaining the above bijection between Δ and maps for performance reasons
|
||
|
||
;; TODO: This is doing too many things
|
||
;; NB: Depends on clause order
|
||
(define-metafunction ttL
|
||
Δ-ref-type : Δ x -> t or #f
|
||
[(Δ-ref-type ∅ x) #f]
|
||
[(Δ-ref-type (Δ (x : t any)) x) t]
|
||
[(Δ-ref-type (Δ (x_0 : t_0 ((x_1 : t_1) ... (x : t) (x_2 : t_2) ...))) x) t]
|
||
[(Δ-ref-type (Δ (x_0 : t_0 any)) x) (Δ-ref-type Δ x)])
|
||
|
||
(define-metafunction ttL
|
||
Δ-set : Δ x t ((x : t) ...) -> Δ
|
||
[(Δ-set Δ x t any) (Δ (x : t any))])
|
||
|
||
(define-metafunction ttL
|
||
Δ-union : Δ Δ -> Δ
|
||
[(Δ-union Δ ∅) Δ]
|
||
[(Δ-union Δ_2 (Δ_1 (x : t any)))
|
||
((Δ-union Δ_2 Δ_1) (x : t any))])
|
||
|
||
;; Returns the inductively defined type that x constructs
|
||
;; NB: Depends on clause order
|
||
(define-metafunction ttL
|
||
Δ-key-by-constructor : Δ x -> x
|
||
[(Δ-key-by-constructor (Δ (x : t ((x_0 : t_0) ... (x_c : t_c) (x_1 : t_1) ...))) x_c)
|
||
x]
|
||
[(Δ-key-by-constructor (Δ (x_1 : t_1 any)) x)
|
||
(Δ-key-by-constructor Δ x)])
|
||
|
||
;; Returns the constructor map for the inductively defined type x_D in the signature Δ
|
||
(define-metafunction ttL
|
||
Δ-ref-constructor-map : Δ x -> ((x : t) ...) or #f
|
||
;; NB: Depends on clause order
|
||
[(Δ-ref-constructor-map ∅ x_D) #f]
|
||
[(Δ-ref-constructor-map (Δ (x_D : t_D any)) x_D)
|
||
any]
|
||
[(Δ-ref-constructor-map (Δ (x_1 : t_1 any)) x_D)
|
||
(Δ-ref-constructor-map Δ x_D)])
|
||
|
||
;; TODO: Should not use Δ-ref-type
|
||
(define-metafunction ttL
|
||
Δ-ref-constructor-type : Δ x x -> t
|
||
[(Δ-ref-constructor-type Δ x_D x_ci)
|
||
(Δ-ref-type Δ x_ci)])
|
||
|
||
;; Get the list of constructors for the inducitvely defined type x_D
|
||
;; NB: Depends on clause order
|
||
(define-metafunction ttL
|
||
Δ-ref-constructors : Δ x -> (x ...) or #f
|
||
[(Δ-ref-constructors ∅ x_D) #f]
|
||
[(Δ-ref-constructors (Δ (x_D : t_D ((x : t) ...))) x_D)
|
||
(x ...)]
|
||
[(Δ-ref-constructors (Δ (x_1 : t_1 any)) x_D)
|
||
(Δ-ref-constructors Δ x_D)])
|
||
|
||
;; NB: Depends on clause order
|
||
(define-metafunction ttL
|
||
sequence-index-of : any (any ...) -> natural
|
||
[(sequence-index-of any_0 (any_0 any ...))
|
||
0]
|
||
[(sequence-index-of any_0 (any_1 any ...))
|
||
,(add1 (term (sequence-index-of any_0 (any ...))))])
|
||
|
||
;; Get the index of the constructor x_ci in the list of constructors for x_D
|
||
(define-metafunction ttL
|
||
Δ-constructor-index : Δ x x -> natural
|
||
[(Δ-constructor-index Δ x_D x_ci)
|
||
(sequence-index-of x_ci (Δ-ref-constructors Δ x_D))])
|
||
|
||
;;; ------------------------------------------------------------------------
|
||
;;; Operations that involve contexts.
|
||
|
||
(define-extended-language tt-ctxtL ttL
|
||
;; Telescope.
|
||
;; NB: There is a bijection between this an a vector of maps from x to t
|
||
(Ξ Φ ::= hole (Π (x : t) Ξ))
|
||
;; Apply context
|
||
;; NB: There is a bijection between this an a vector expressions
|
||
(Θ ::= hole (Θ e)))
|
||
|
||
(define Ξ? (redex-match? tt-ctxtL Ξ))
|
||
(define Φ? (redex-match? tt-ctxtL Φ))
|
||
(define Θ? (redex-match? tt-ctxtL Θ))
|
||
|
||
;; TODO: Might be worth it to actually maintain the above bijections, for performance reasons.
|
||
|
||
;; Return the parameters of x_D as a telescope Ξ
|
||
;; TODO: Define generic traversals of Δ and Γ ?
|
||
(define-metafunction tt-ctxtL
|
||
Δ-ref-parameter-Ξ : Δ x -> Ξ
|
||
[(Δ-ref-parameter-Ξ (Δ (x_D : (in-hole Ξ U) any)) x_D)
|
||
Ξ]
|
||
[(Δ-ref-parameter-Ξ (Δ (x_1 : t_1 any)) x_D)
|
||
(Δ-ref-parameter-Ξ Δ x_D)])
|
||
|
||
;; Applies the term t to the telescope Ξ.
|
||
;; TODO: Test
|
||
#| TODO:
|
||
| This essentially eta-expands t at the type-level. Why is this necessary? Shouldn't it be true
|
||
| that (equivalent t (Ξ-apply Ξ t))?
|
||
| Maybe not. t is a lambda whose type is equivalent to (Ξ-apply Ξ t)? Yes.
|
||
|#
|
||
(define-metafunction tt-ctxtL
|
||
Ξ-apply : Ξ t -> t
|
||
[(Ξ-apply hole t) t]
|
||
[(Ξ-apply (Π (x : t) Ξ) t_0) (Ξ-apply Ξ (t_0 x))])
|
||
|
||
;; Compose multiple telescopes into a single telescope:
|
||
(define-metafunction tt-ctxtL
|
||
Ξ-compose : Ξ Ξ ... -> Ξ
|
||
[(Ξ-compose Ξ) Ξ]
|
||
[(Ξ-compose Ξ_0 Ξ_1 Ξ_rest ...)
|
||
(Ξ-compose (in-hole Ξ_0 Ξ_1) Ξ_rest ...)])
|
||
|
||
;; Compute the number of arguments in a Ξ
|
||
(define-metafunction tt-ctxtL
|
||
Ξ-length : Ξ -> natural
|
||
[(Ξ-length hole) 0]
|
||
[(Ξ-length (Π (x : t) Ξ)) ,(add1 (term (Ξ-length Ξ)))])
|
||
|
||
;; Compute the number of applications in a Θ
|
||
(define-metafunction tt-ctxtL
|
||
Θ-length : Θ -> natural
|
||
[(Θ-length hole) 0]
|
||
[(Θ-length (Θ e)) ,(add1 (term (Θ-length Θ)))])
|
||
|
||
;; Reference an expression in Θ by index; index 0 corresponds to the the expression applied to a hole.
|
||
(define-metafunction tt-ctxtL
|
||
Θ-ref : Θ natural -> e or #f
|
||
[(Θ-ref hole natural) #f]
|
||
[(Θ-ref (in-hole Θ (hole e)) 0) e]
|
||
[(Θ-ref (in-hole Θ (hole e)) natural) (Θ-ref Θ ,(sub1 (term natural)))])
|
||
|
||
;;; ------------------------------------------------------------------------
|
||
;;; Computing the types of eliminators
|
||
|
||
;; Returns the telescope of the arguments for the constructor x_ci of the inductively defined type x_D
|
||
(define-metafunction tt-ctxtL
|
||
Δ-constructor-telescope : Δ x x -> Ξ
|
||
[(Δ-constructor-telescope Δ x_D x_ci)
|
||
Ξ
|
||
(where (in-hole Ξ (in-hole Θ x_D))
|
||
(Δ-ref-constructor-type Δ x_D x_ci))])
|
||
|
||
;; Returns the parameter arguments as an apply context of the constructor x_ci of the inductively
|
||
;; defined type x_D
|
||
(define-metafunction tt-ctxtL
|
||
Δ-constructor-parameters : Δ x x -> Θ
|
||
[(Δ-constructor-parameters Δ x_D x_ci)
|
||
Θ
|
||
(where (in-hole Ξ (in-hole Θ x_D))
|
||
(Δ-ref-constructor-type Δ x_D x_ci))])
|
||
|
||
;; Inner loop for Δ-constructor-noninductive-telescope
|
||
(define-metafunction tt-ctxtL
|
||
noninductive-loop : x Φ -> Φ
|
||
[(noninductive-loop x_D hole) hole]
|
||
[(noninductive-loop x_D (Π (x : (in-hole Φ (in-hole Θ x_D))) Φ_1))
|
||
(noninductive-loop x_D Φ_1)]
|
||
[(noninductive-loop x_D (Π (x : t) Φ_1))
|
||
(Π (x : t) (noninductive-loop x_D Φ_1))])
|
||
|
||
;; Returns the noninductive arguments to the constructor x_ci of the inductively defined type x_D
|
||
(define-metafunction tt-ctxtL
|
||
Δ-constructor-noninductive-telescope : Δ x x -> Ξ
|
||
[(Δ-constructor-noninductive-telescope Δ x_D x_ci)
|
||
(noninductive-loop x_D (Δ-constructor-telescope Δ x_D x_ci))])
|
||
|
||
;; Inner loop for Δ-constructor-inductive-telescope
|
||
;; NB: Depends on clause order
|
||
(define-metafunction tt-ctxtL
|
||
inductive-loop : x Φ -> Φ
|
||
[(inductive-loop x_D hole) hole]
|
||
[(inductive-loop x_D (Π (x : (in-hole Φ (in-hole Θ x_D))) Φ_1))
|
||
(Π (x : (in-hole Φ (in-hole Θ x_D))) (inductive-loop x_D Φ_1))]
|
||
[(inductive-loop x_D (Π (x : t) Φ_1))
|
||
(inductive-loop x_D Φ_1)])
|
||
|
||
;; Returns the inductive arguments to the constructor x_ci of the inducitvely defined type x_D
|
||
(define-metafunction tt-ctxtL
|
||
Δ-constructor-inductive-telescope : Δ x x -> Ξ
|
||
[(Δ-constructor-inductive-telescope Δ x_D x_ci)
|
||
(inductive-loop x_D (Δ-constructor-telescope Δ x_D x_ci))])
|
||
|
||
;; Returns the inductive hypotheses required for eliminating the inductively defined type x_D with
|
||
;; motive t_P, where the telescope Φ are the inductive arguments to a constructor for x_D
|
||
(define-metafunction tt-ctxtL
|
||
hypotheses-loop : x t Φ -> Φ
|
||
[(hypotheses-loop x_D t_P hole) hole]
|
||
[(hypotheses-loop x_D t_P (name any_0 (Π (x : (in-hole Φ (in-hole Θ x_D))) Φ_1)))
|
||
;; TODO: Instead of this nonsense, it might be simpler to pass in the type of t_P and use that
|
||
;; as/to compute the type of the hypothesis.
|
||
(Π (x_h : (in-hole Φ ((in-hole Θ t_P) (Ξ-apply Φ x))))
|
||
(hypotheses-loop x_D t_P Φ_1))
|
||
(where x_h ,(variable-not-in (term (x_D t_P any_0)) 'x-ih))])
|
||
|
||
;; Returns the inductive hypotheses required for the elimination method of constructor x_ci for
|
||
;; inductive type x_D, when eliminating with motive t_P.
|
||
(define-metafunction tt-ctxtL
|
||
Δ-constructor-inductive-hypotheses : Δ x x t -> Ξ
|
||
[(Δ-constructor-inductive-hypotheses Δ x_D x_ci t_P)
|
||
(hypotheses-loop x_D t_P (Δ-constructor-inductive-telescope Δ x_D x_ci))])
|
||
|
||
(define-metafunction tt-ctxtL
|
||
Δ-constructor-method-telescope : Δ x x t -> Ξ
|
||
[(Δ-constructor-method-telescope Δ x_D x_ci t_P)
|
||
(Π (x_mi : (in-hole Ξ_a (in-hole Ξ_h ((in-hole Θ_p t_P) (Ξ-apply Ξ_a x_ci)))))
|
||
hole)
|
||
(where Θ_p (Δ-constructor-parameters Δ x_D x_ci))
|
||
(where Ξ_a (Δ-constructor-telescope Δ x_D x_ci))
|
||
(where Ξ_h (Δ-constructor-inductive-hypotheses Δ x_D x_ci t_P))
|
||
(where x_mi ,(variable-not-in (term (t_P Δ)) 'x-mi))])
|
||
|
||
;; fold Ξ-compose over map Δ-constructor-method-telescope over the list of constructors
|
||
(define-metafunction tt-ctxtL
|
||
method-loop : Δ x t (x ...) -> Ξ
|
||
[(method-loop Δ x_D t_P ()) hole]
|
||
[(method-loop Δ x_D t_P (x_0 x_rest ...))
|
||
(Ξ-compose (Δ-constructor-method-telescope Δ x_D x_0 t_P) (method-loop Δ x_D t_P (x_rest ...)))])
|
||
|
||
;; Returns the telescope of all methods required to eliminate the type x_D with motive t_P
|
||
(define-metafunction tt-ctxtL
|
||
Δ-methods-telescope : Δ x t -> Ξ
|
||
[(Δ-methods-telescope Δ x_D t_P)
|
||
(method-loop Δ x_D t_P (Δ-ref-constructors Δ x_D))])
|
||
|
||
;; Computes the type of the eliminator for the inductively defined type x_D with a motive whose result
|
||
;; is in universe U.
|
||
;;
|
||
;; The type of (elim x_D U) is something like:
|
||
;; (∀ (P : (∀ a -> ... -> (D a ...) -> U))
|
||
;; (method_ci ...) -> ... ->
|
||
;; (a -> ... -> (D a ...) ->
|
||
;; (P a ... (D a ...))))
|
||
;;
|
||
;; x_D is an inductively defined type
|
||
;; U is the sort the motive
|
||
;; x_P is the name of the motive
|
||
;; Ξ_P*D is the telescope of the parameters of x_D and
|
||
;; the witness of type x_D (applied to the parameters)
|
||
;; Ξ_m is the telescope of the methods for x_D
|
||
(define-metafunction tt-ctxtL
|
||
Δ-elim-type : Δ x U -> t
|
||
[(Δ-elim-type Δ x_D U)
|
||
(Π (x_P : (in-hole Ξ_P*D U))
|
||
;; The methods Ξ_m for each constructor of type x_D
|
||
(in-hole Ξ_m
|
||
;; And finally, the parameters and discriminant
|
||
(in-hole Ξ_P*D
|
||
;; The result is (P a ... (x_D a ...)), i.e., the motive
|
||
;; applied to the paramters and discriminant
|
||
(Ξ-apply Ξ_P*D x_P))))
|
||
;; Get the parameters of x_D
|
||
(where Ξ (Δ-ref-parameter-Ξ Δ x_D))
|
||
;; A fresh name to bind the discriminant
|
||
(where x ,(variable-not-in (term (Δ Γ x_D Ξ)) 'x-D))
|
||
;; The telescope (∀ a -> ... -> (D a ...) hole), i.e.,
|
||
;; of the parameters and the inductive type applied to the
|
||
;; parameters
|
||
(where Ξ_P*D (in-hole Ξ (Π (x : (Ξ-apply Ξ x_D)) hole)))
|
||
;; A fresh name for the motive
|
||
(where x_P ,(variable-not-in (term (Δ Γ x_D Ξ Ξ_P*D x)) 'x-P))
|
||
;; The types of the methods for this inductive.
|
||
(where Ξ_m (Δ-methods-telescope Δ x_D x_P))])
|
||
|
||
;; TODO: This might belong in the next section, since it's related to evaluation
|
||
;; Generate recursive applications of the eliminator for each inductive argument of type x_D.
|
||
;; In more detaill, given motive t_P, parameters Θ_p, methods Θ_m, and arguments Θ_i to constructor
|
||
;; x_ci for x_D, for each inductively smaller term t_i of type (in-hole Θ_p x_D) inside Θ_i,
|
||
;; generate: (elim x_D U t_P Θ_m ... Θ_p ... t_i)
|
||
(define-metafunction tt-ctxtL
|
||
Δ-inductive-elim : Δ x U t Θ Θ Θ -> Θ
|
||
[(Δ-inductive-elim Δ x_D U t_P Θ_p Θ_m (in-hole Θ_i (hole (name t_i (in-hole Θ_r x_ci)))))
|
||
((Δ-inductive-elim Δ x_D U t_P Θ_p Θ_m Θ_i)
|
||
(in-hole ((in-hole Θ_p Θ_m) t_i) ((elim x_D U) t_P)))
|
||
(side-condition (memq (term x_ci) (term (Δ-ref-constructors Δ x_D))))]
|
||
[(Δ-inductive-elim Δ x_D U t_P Θ_p Θ_m Θ_nr) hole])
|
||
|
||
;;; ------------------------------------------------------------------------
|
||
;;; Dynamic semantics
|
||
;;; The majority of this section is dedicated to evaluation of (elim x U), the eliminator for the
|
||
;;; inductively defined type x with a motive whose result is in universe U
|
||
|
||
(define-extended-language tt-redL tt-ctxtL
|
||
;; NB: (in-hole Θv (elim x U)) is only a value when it's a partially applied elim. However,
|
||
;; determining whether or not it is partially applied cannot be done with the grammar alone.
|
||
(v ::= x U (Π (x : t) t) (λ (x : t) t) (elim x U) (in-hole Θv x) (in-hole Θv (elim x U)))
|
||
(Θv ::= hole (Θv v))
|
||
;; call-by-value, plus reduce under Π (helps with typing checking)
|
||
(E ::= hole (E e) (v E) (Π (x : v) E) (Π (x : E) e)))
|
||
|
||
(define Θv? (redex-match? tt-redL Θv))
|
||
(define E? (redex-match? tt-redL E))
|
||
(define v? (redex-match? tt-redL v))
|
||
|
||
(define current-Δ (make-parameter (term ∅)))
|
||
(define tt-->
|
||
(reduction-relation tt-redL
|
||
(--> (in-hole E ((λ (x : t_0) t_1) t_2))
|
||
(in-hole E (subst t_1 x t_2))
|
||
-->β)
|
||
(--> (in-hole E (in-hole Θv ((elim x_D U) v_P)))
|
||
(in-hole E (in-hole Θ_r (in-hole Θv_i v_mi)))
|
||
#|
|
||
| The elim form must appear applied like so:
|
||
| (elim x_D U v_P m_0 ... m_i m_j ... m_n p ... (c_i a ...))
|
||
|
|
||
| Where:
|
||
| x_D is the inductive being eliminated
|
||
| U is the universe of the result of the motive
|
||
| v_P is the motive
|
||
| m_{0..n} are the methods
|
||
| p ... are the parameters of x_D
|
||
| c_i is a constructor of x_d
|
||
| a ... are the arguments to c_i
|
||
| Unfortunately, Θ contexts turn all this inside out:
|
||
| TODO: Write better abstractions for this notation
|
||
|#
|
||
(where Δ ,(current-Δ))
|
||
;; Split Θv into its components: the paramters Θv_P for x_D, the methods Θv_m for x_D, and
|
||
;; the discriminant: the constructor x_ci applied to its argument Θv_i
|
||
(where (in-hole (Θv_p (in-hole Θv_i x_ci)) Θv_m) Θv)
|
||
;; Check that Θ_p actually matches the parameters of x_D, to ensure it doesn't capture other
|
||
;; arguments.
|
||
(side-condition (equal? (term (Θ-length Θv_p)) (term (Ξ-length (Δ-ref-parameter-Ξ Δ x_D)))))
|
||
;; Ensure x_ci is actually a constructor for x_D
|
||
(where (x_c* ...) (Δ-ref-constructors Δ x_D))
|
||
(side-condition (memq (term x_ci) (term (x_c* ...))))
|
||
;; There should be a number of methods equal to the number of constructors; to ensure E
|
||
;; doesn't capture methods and Θv_m doesn't capture other arguments
|
||
(side-condition (equal? (length (term (x_c* ...))) (term (Θ-length Θv_m))))
|
||
;; Find the method for constructor x_ci, relying on the order of the arguments.
|
||
(where v_mi (Θ-ref Θv_m (Δ-constructor-index Δ x_D x_ci)))
|
||
;; Generate the inductive recursion
|
||
(where Θ_r (Δ-inductive-elim Δ x_D U v_P Θv_p Θv_m Θv_i))
|
||
-->elim)))
|
||
|
||
(define reduce-memoize (make-hash))
|
||
(define-metafunction tt-redL
|
||
step : Δ e -> e
|
||
[(step Δ e)
|
||
e_r
|
||
(where e_r ,(dict-ref reduce-memoize (term e)
|
||
(thunk
|
||
(parameterize ([current-Δ (term Δ)])
|
||
(let ([x (car (apply-reduction-relation tt--> (term e)))])
|
||
(dict-set! reduce-memoize (term e_r) x)
|
||
x)))))])
|
||
|
||
(define-metafunction tt-redL
|
||
reduce : Δ e -> e
|
||
[(reduce Δ e)
|
||
e_r
|
||
(where e_r ,(dict-ref reduce-memoize (term e)
|
||
(thunk
|
||
(parameterize ([current-Δ (term Δ)])
|
||
(let ([x (car (apply-reduction-relation* tt--> (term e) #:cache-all? #t))])
|
||
(dict-set! reduce-memoize (term e_r) x)
|
||
x)))))])
|
||
|
||
(define-judgment-form tt-redL
|
||
#:mode (equivalent I I I)
|
||
#:contract (equivalent Δ t t)
|
||
|
||
[(where t_2 (reduce Δ t_0))
|
||
(where t_3 (reduce Δ t_1))
|
||
(side-condition (α-equivalent? t_2 t_3))
|
||
----------------- "≡-αβ"
|
||
(equivalent Δ t_0 t_1)])
|
||
|
||
;;; ------------------------------------------------------------------------
|
||
;;; Type checking and synthesis
|
||
|
||
(define-extended-language tt-typingL tt-redL
|
||
;; NB: There may be a bijection between Γ and Ξ. That's interesting.
|
||
;; NB: Also a bijection between Γ and a list of maps from x to t.
|
||
(Γ ::= ∅ (Γ x : t)))
|
||
(define Γ? (redex-match? tt-typingL Γ))
|
||
|
||
(define-metafunction tt-typingL
|
||
Γ-union : Γ Γ -> Γ
|
||
[(Γ-union Γ ∅) Γ]
|
||
[(Γ-union Γ_2 (Γ_1 x : t))
|
||
((Γ-union Γ_2 Γ_1) x : t)])
|
||
|
||
(define-metafunction tt-typingL
|
||
Γ-set : Γ x t -> Γ
|
||
[(Γ-set Γ x t) (Γ x : t)])
|
||
|
||
;; NB: Depends on clause order
|
||
(define-metafunction tt-typingL
|
||
Γ-ref : Γ x -> t or #f
|
||
[(Γ-ref ∅ x) #f]
|
||
[(Γ-ref (Γ x : t) x) t]
|
||
[(Γ-ref (Γ x_0 : t_0) x_1) (Γ-ref Γ x_1)])
|
||
|
||
;; NB: Depends on clause order
|
||
(define-metafunction tt-typingL
|
||
Γ-remove : Γ x -> Γ
|
||
[(Γ-remove ∅ x) ∅]
|
||
[(Γ-remove (Γ x : t) x) Γ]
|
||
[(Γ-remove (Γ x_0 : t_0) x_1) (Γ-remove Γ x_1)])
|
||
|
||
(define-metafunction tt-typingL
|
||
nonpositive : x t -> #t or #f
|
||
[(nonpositive x (in-hole Θ x))
|
||
#t]
|
||
[(nonpositive x (Π (x_0 : (in-hole Θ x)) t))
|
||
#f]
|
||
[(nonpositive x (Π (x_0 : t_0) t))
|
||
,(and (term (positive x t_0)) (term (nonpositive x t)))]
|
||
[(nonpositive x t) #t])
|
||
|
||
(define-metafunction tt-typingL
|
||
positive : x t -> #t or #f
|
||
[(positive x (in-hole Θ x))
|
||
#f]
|
||
[(positive x (Π (x_0 : (in-hole Θ x)) t))
|
||
(positive x t)]
|
||
[(positive x (Π (x_0 : t_0) t))
|
||
,(and (term (nonpositive x t_0)) (term (positive x t)))]
|
||
[(positive x t) #t])
|
||
|
||
(define-metafunction tt-typingL
|
||
positive* : x (t ...) -> #t or #f
|
||
[(positive* x_D ()) #t]
|
||
[(positive* x_D (t_c t_rest ...))
|
||
;; Replace the result of the constructor with (Unv 0), to avoid the result being considered a
|
||
;; nonpositive position.
|
||
,(and (term (positive x_D (in-hole Ξ (Unv 0)))) (term (positive* x_D (t_rest ...))))
|
||
(where (in-hole Ξ (in-hole Θ x_D)) t_c)])
|
||
|
||
;; Holds when the signature Δ and typing context Γ are well-formed.
|
||
(define-judgment-form tt-typingL
|
||
#:mode (wf I I)
|
||
#:contract (wf Δ Γ)
|
||
|
||
[----------------- "WF-Empty"
|
||
(wf ∅ ∅)]
|
||
|
||
[(type-infer Δ Γ t t_0)
|
||
(wf Δ Γ)
|
||
----------------- "WF-Var"
|
||
(wf Δ (Γ x : t))]
|
||
|
||
[(wf Δ ∅)
|
||
(type-infer Δ ∅ t_D U_D)
|
||
(type-infer Δ (∅ x_D : t_D) t_c U_c) ...
|
||
;; NB: Ugh this should be possible with pattern matching alone ....
|
||
(side-condition ,(map (curry equal? (term x_D)) (term (x_D* ...))))
|
||
(side-condition (positive* x_D (t_c ...)))
|
||
----------------- "WF-Inductive"
|
||
(wf (Δ (x_D : t_D
|
||
;; Checks that a constructor for x actually produces an x, i.e., that
|
||
;; the constructor is well-formed.
|
||
((x_c : (name t_c (in-hole Ξ (in-hole Θ x_D*)))) ...))) ∅)])
|
||
|
||
;; TODO: Bi-directional and inference?
|
||
;; TODO: http://www.cs.ox.ac.uk/ralf.hinze/WG2.8/31/slides/stephanie.pdf
|
||
|
||
;; Holds when e has type t under signature Δ and typing context Γ
|
||
(define-judgment-form tt-typingL
|
||
#:mode (type-infer I I I O)
|
||
#:contract (type-infer Δ Γ e t)
|
||
|
||
[(wf Δ Γ)
|
||
(unv-type U_0 U_1)
|
||
----------------- "DTR-Unv"
|
||
(type-infer Δ Γ U_0 U_1)]
|
||
|
||
[(where t (Δ-ref-type Δ x))
|
||
----------------- "DTR-Inductive"
|
||
(type-infer Δ Γ x t)]
|
||
|
||
[(where t (Γ-ref Γ x))
|
||
----------------- "DTR-Start"
|
||
(type-infer Δ Γ x t)]
|
||
|
||
[(type-infer Δ (Γ x : t_0) e t_1)
|
||
(type-infer Δ Γ (Π (x : t_0) t_1) U)
|
||
----------------- "DTR-Abstraction"
|
||
(type-infer Δ Γ (λ (x : t_0) e) (Π (x : t_0) t_1))]
|
||
|
||
[(type-infer Δ Γ t_0 U_1)
|
||
(type-infer Δ (Γ x : t_0) t U_2)
|
||
(unv-pred U_1 U_2 U)
|
||
----------------- "DTR-Product"
|
||
(type-infer Δ Γ (Π (x : t_0) t) U)]
|
||
|
||
[(type-infer Δ Γ e_0 t)
|
||
;; Cannot rely on type-infer producing normal forms.
|
||
(where (Π (x_0 : t_0) t_1) (reduce Δ t))
|
||
(type-check Δ Γ e_1 t_0)
|
||
(where t_3 (subst t_1 x_0 e_1))
|
||
----------------- "DTR-Application"
|
||
(type-infer Δ Γ (e_0 e_1) t_3)]
|
||
|
||
[(where t (Δ-elim-type Δ D U))
|
||
(type-infer Δ Γ t U_e)
|
||
----------------- "DTR-Elim_D"
|
||
(type-infer Δ Γ (elim D U) t)])
|
||
|
||
(define-judgment-form tt-typingL
|
||
#:mode (type-check I I I I)
|
||
#:contract (type-check Δ Γ e t)
|
||
|
||
[(type-infer Δ Γ e t_0)
|
||
(equivalent Δ t t_0)
|
||
----------------- "DTR-Check"
|
||
(type-check Δ Γ e t)])
|