modernize stlc.rkt and eliminate ellipses so that well-typed generation works

This commit is contained in:
Robby Findler 2014-08-05 01:55:00 -05:00
parent 106cd16d35
commit a9ce8bfd65

View File

@ -1,56 +1,63 @@
#lang racket
(require redex)
(provide λv red typeof)
(provide λ λv red typeof)
(define-language λv
(e (e e ...) (if0 e e e) (+ e e) x v)
(v (λ ((x t) ...) e) number)
(t (t ... -> t) num)
(E (v ... E e ...) (if0 E e e) (+ E e) (+ v E) hole)
(x variable-not-otherwise-mentioned)
(G ([x t] ...)))
(define-language λ
(e (e e)
x
(λ (x t) e)
(if0 e e e)
(+ e e)
number)
(t (t -> t) num)
(x variable-not-otherwise-mentioned))
(define-extended-language λv λ
(v (λ (x t) e) number)
(E hole
(v E) (E e)
(if0 E e e)
(+ E e) (+ v E))
(Γ · (x t Γ)))
(define red
(reduction-relation
λv
(--> (in-hole E (+ number_1 number_2))
(in-hole E ,(+ (term number_1)
(term number_2)))
(in-hole E (Σ number_1 number_2))
"+")
(--> (in-hole E (if0 0 e_1 e_2))
(in-hole E e_1)
"if0t")
(--> (in-hole E (if0 number_1 e_1 e_2))
(--> (in-hole E (if0 number e_1 e_2))
(in-hole E e_2)
"if0f"
(side-condition
(not (= 0 (term number_1)))))
(--> (in-hole E ((λ ((x t) ..._1) e) v ..._1))
(in-hole E (subst-n (x v) ... e))
(not (= 0 (term number)))))
(--> (in-hole E ((λ (x t) e) v))
(in-hole E (subst x v e))
"βv")))
(define-metafunction λv
subst-n : (x any) ... any -> any
[(subst-n (x_1 any_1) (x_2 any_2) ... any_3)
(subst x_1 any_1 (subst-n (x_2 any_2) ...
any_3))]
[(subst-n any_3) any_3])
Σ : number number -> number
[(Σ number_1 number_2)
,(+ (term number_1) (term number_2))])
(define-metafunction λv
subst : x any any -> any
;; 1. x_1 bound, so don't continue in λ body
[(subst x_1 any_1 (λ ((x_2 t_2) ... (x_1 t_1) (x_3 t_3) ...) any_2))
(λ ((x_2 t_2) ... (x_1 t_1) (x_3 t_3) ...) any_2)]
[(subst x_1 any_1 (λ (x_1 t_1) any_2))
(λ (x_1 t_1) any_2)]
;; 2. general purpose capture avoiding case
[(subst x_1 any_1 (λ ((x_2 t_2) ...) any_2))
(λ ((x_new t_2) ...)
[(subst x_1 any_1 (λ (x_2 t_2) any_2))
(λ (x_new t_2)
(subst x_1 any_1
(subst-vars (x_2 x_new) ...
any_2)))
(where (x_new ...)
(subst-var x_2 x_new
any_2)))
(where (x_new)
,(variables-not-in
(term (x_1 any_1 any_2))
(term (x_2 ...))))]
(term (x_2))))]
;; 3. replace x_1 with e_1
[(subst x_1 any_1 x_1) any_1]
;; 4. x_1 and x_2 are different, so don't replace
@ -61,103 +68,125 @@
[(subst x_1 any_1 any_2) any_2])
(define-metafunction λv
subst-vars : (x any) ... any -> any
[(subst-vars (x_1 any_1) x_1) any_1]
[(subst-vars (x_1 any_1) (any_2 ...))
((subst-vars (x_1 any_1) any_2) ...)]
[(subst-vars (x_1 any_1) any_2) any_2]
[(subst-vars (x_1 any_1) (x_2 any_2) ... any_3)
(subst-vars (x_1 any_1)
(subst-vars (x_2 any_2) ... any_3))]
[(subst-vars any) any])
subst-var : x any any -> any
[(subst-var x_1 any_1 x_1) any_1]
[(subst-var x_1 any_1 (any_2 ...))
((subst-var x_1 any_1 any_2) ...)]
[(subst-var x_1 any_1 any_2) any_2])
(define-judgment-form λv
#:mode (typeof I I O)
#:contract (typeof G e t)
[(typeof G number num)]
[(typeof G (+ e_1 e_2) num)
(typeof G e_1 num)
(typeof G e_2 num)]
[(typeof G (if0 e_1 e_2 e_3) t)
(typeof G e_1 num)
(typeof G e_2 t)
(typeof G e_3 t)]
[(typeof G x t)
(where t (lookup G x))]
[(typeof G (e_1 e_2 ...) t)
(typeof G e_1 (t_2 ... -> t))
(typeof G e_2 t_2) ...]
[(typeof G (λ ((x_1 t_1) ...) e) (t_1 ... -> t))
(typeof (extend G [x_1 t_1] ...) e t)])
#:contract (typeof Γ e t)
[---------------------
(typeof Γ number num)]
[(typeof Γ e_1 num)
(typeof Γ e_2 num)
--------------------------
(typeof Γ (+ e_1 e_2) num)]
[(typeof Γ e_1 num)
(typeof Γ e_2 t)
(typeof Γ e_3 t)
------------------------------
(typeof Γ (if0 e_1 e_2 e_3) t)]
[(where t (lookup Γ x))
----------------------
(typeof Γ x t)]
[(typeof Γ e_1 (t_2 -> t))
(typeof Γ e_2 t_2)
--------------------------
(typeof Γ (e_1 e_2) t)]
[(typeof (x_1 t_1 Γ) e t)
----------------------------------------
(typeof Γ (λ (x_1 t_1) e) (t_1 -> t))])
(define-metafunction λv
lookup : G x -> t or #f
[(lookup ([x_0 t_0] ... [x_i t_i] [x_i+1 t_i+1] ...) x_i)
t_i]
[(lookup G x) #f])
lookup : Γ x -> t or #f
[(lookup (x t Γ) x) t]
[(lookup (x_1 t Γ) x_2) (lookup Γ x_2)]
[(lookup · x) #f])
(define-metafunction λv
extend : G [x t] ... -> G
[(extend G) G]
[(extend ([x_0 t_0] ... [x_i t_i] [x_i+1 t_i+1] ...) [x_i t] [x_i+2 t_i+2] ...)
(extend ([x_0 t_0] ... [x_i t] [x_i+1 t_i+1] ...) [x_i+2 t_i+2] ...)]
[(extend ([x_0 t_0] ...) [x_i t_i] [x_i+1 t_i+1] ...)
(extend ([x_0 t_0] ... [x_i t_i]) [x_i+1 t_i+1] ...)])
;; remove the #; to run an example
;; remove this #; to run an example
#;
(traces red
(term
(+ ((λ ((n num))
(+ ((λ (n num)
(if0 n
1
0))
(+ 2 2))
2)))
(test-equal (term (subst x y x)) (term y))
(test-equal (term (subst x y z)) (term z))
(test-equal (term (subst x y (x (y z)))) (term (y (y z))))
(test-equal (term (subst x y ((λ ((x num)) x) ((λ ((y1 num)) y1) (λ ((x num)) z)))))
(term ((λ ((x num)) x) ((λ ((y2 num)) y2) (λ ((x num)) z)))))
(test-equal (term (subst x y (if0 (+ 1 x) x x)))
(term (if0 (+ 1 y) y y)))
(test-equal (term (subst x (λ ((z num)) y) (λ ((y num)) x)))
(term (λ ((y1 num)) (λ ((z num)) y))))
(test-equal (term (subst x 1 (λ ((y num)) x)))
(term (λ ((y num)) 1)))
(test-equal (term (subst x y (λ ((y num)) x)))
(term (λ ((y1 num)) y)))
(test-equal (term (subst x (λ ((y num)) y) (λ ((z num)) (z2 z))))
(term (λ ((z1 num)) (z2 z1))))
(test-equal (term (subst x (λ ((z num)) z) (λ ((z num)) (z1 z))))
(term (λ ((z2 num)) (z1 z2))))
(test-equal (term (subst x z (λ ((z num)) (z1 z))))
(term (λ ((z2 num)) (z1 z2))))
(test-equal (term (subst x3 5 (λ ((x2 num)) x2)))
(term (λ ((x1 num)) x1)))
(test-equal (term (subst z * (λ ((z num) (x num)) 1)))
(term (λ ((z num) (x num)) 1)))
(test-equal (term (subst q (λ ((x num)) z) (λ ((z num) (x num)) q)))
(term (λ ((z1 num) (x1 num)) (λ ((x num)) z))))
(test-equal (term (subst x 1 (λ ((x num) (x num)) x)))
(term (λ ((x num) (x num)) x)))
;; remove this #; to generate a random well-typed term
#;
(generate-term λv #:satisfying (typeof · e num) 5)
(test-->> red (term ((λ ((x num)) x) 1)) 1)
(test-->> red (term ((λ ((x num) (y num)) x) 1 2)) 1)
(test-->> red (term ((λ ((x num) (y num)) y) 1 2)) 2)
(test-->> red (term (((λ ((x num)) (λ ((x num)) x)) 1) 2)) 2)
(test-->> red (term (((λ ((x num)) (λ ((y num)) x)) 1) 2)) 1)
(test-->> red (term ((λ ((x num)) (+ x x)) 2)) 4)
(test-->> red (term ((λ ((x num)) (if0 x x (+ x 1))) 2)) 3)
(test-->> red (term ((λ ((x num)) (if0 x x (+ x 1))) 0)) 0)
(define (preservation e)
(define types (judgment-holds (typeof · ,e t) t))
(unless (null? types)
(unless (= 1 (length types)) (error 'preservation "multiple types! ~s" e)))
(cond
[(null? types) #t]
[else
(for/and ([v (apply-reduction-relation* red e)])
(equal? (judgment-holds (typeof · ,v t) t)
types))]))
(define (try-it)
(redex-check λv
#:satisfying (typeof · e num)
(preservation (term e))))
(test-->> red (term ((λ (x num) x) 1)) 1)
(test-->> red (term (((λ (x num) (λ (y num) x)) 1) 2)) 1)
(test-->> red (term (((λ (x num) (λ (y num) y)) 1) 2)) 2)
(test-->> red (term (((λ (x num) (λ (x num) x)) 1) 2)) 2)
(test-->> red (term (((λ (x num) (λ (y num) x)) 1) 2)) 1)
(test-->> red (term ((λ (x num) (+ x x)) 2)) 4)
(test-->> red (term ((λ (x num) (if0 x x (+ x 1))) 2)) 3)
(test-->> red (term ((λ (x num) (if0 x x (+ x 1))) 0)) 0)
(test-->> red
(term (((λ ((x num)) (λ ((y num) (z num)) x)) 1) 2))
(term ((λ ((y num) (z num)) 1) 2)))
(term (((λ (x num) (λ (y num) (λ (z num) x))) 1) 2))
(term (λ (z num) 1)))
(test-->> red
(term (+ (+ 1 2) (+ 3 4)))
(term 10))
(test-equal (term (subst x y x)) (term y))
(test-equal (term (subst x y z)) (term z))
(test-equal (term (subst x y (x (y z)))) (term (y (y z))))
(test-equal (term (subst x y ((λ (x num) x) ((λ (y1 num) y1) (λ (x num) z)))))
(term ((λ (x num) x) ((λ (y2 num) y2) (λ (x num) z)))))
(test-equal (term (subst x y (if0 (+ 1 x) x x)))
(term (if0 (+ 1 y) y y)))
(test-equal (term (subst x (λ (z num) y) (λ (y num) x)))
(term (λ (y1 num) (λ (z num) y))))
(test-equal (term (subst x 1 (λ (y num) x)))
(term (λ (y num) 1)))
(test-equal (term (subst x y (λ (y num) x)))
(term (λ (y1 num) y)))
(test-equal (term (subst x (λ (y num) y) (λ (z num) (z2 z))))
(term (λ (z1 num) (z2 z1))))
(test-equal (term (subst x (λ (z num) z) (λ (z num) (z1 z))))
(term (λ (z2 num) (z1 z2))))
(test-equal (term (subst x z (λ (z num) (z1 z))))
(term (λ (z2 num) (z1 z2))))
(test-equal (term (subst x3 5 (λ (x2 num) x2)))
(term (λ (x1 num) x1)))
(test-equal (term (subst z * (λ (z num) (λ (x num) 1))))
(term (λ (z num) (λ (x num) 1))))
(test-equal (term (subst q (λ (x num) z) (λ (z num) (λ (x num) q))))
(term (λ (z1 num) (λ (x1 num) (λ (x num) z)))))
(test-equal (term (subst x 1 (λ (x num) (λ (x num) x))))
(term (λ (x num) (λ (x num) x))))
(define (typecheck G e)
(match (judgment-holds (typeof ,G ,e t) t)
[(list) #f]
@ -166,46 +195,48 @@
"multiple typing derivations for term ~a in environment ~a"
e G)]))
(test-equal (typecheck (term ()) (term 1))
(test-equal (typecheck (term ·) (term 1))
(term num))
(test-equal (typecheck (term ()) (term (1 1)))
(test-equal (typecheck (term ·) (term (1 1)))
#f)
(test-equal (typecheck (term ([x num])) (term x))
(test-equal (typecheck (term (x num ·)) (term x))
(term num))
(test-equal (typecheck (term ()) (term x))
(test-equal (typecheck (term ·) (term x))
#f)
(test-equal (typecheck (term ()) (term ((λ ((x num)) x) 1)))
(test-equal (typecheck (term ·) (term ((λ (x num) x) 1)))
(term num))
(test-equal (typecheck (term ()) (term ((λ ((x num)) x) 1 2)))
(test-equal (typecheck (term ·) (term (((λ (x num) x) 1) 2)))
#f)
(test-equal (typecheck (term ())
(term ((λ ((f (num -> num)) (x num))
(f x))
(λ ((x num)) x)
(test-equal (typecheck (term ·)
(term (((λ (f (num -> num))
(λ (x num)
(f x)))
(λ (x num) x))
1)))
(term num))
(test-equal (typecheck (term ())
(term ((λ ((f (num -> num)) (x num))
(f x))
1
(λ ((x num)) x))))
(test-equal (typecheck (term ·)
(term (((λ (f (num -> num))
(λ (x num)
(f x)))
1)
(λ (x num) x))))
#f)
(test-equal (typecheck (term ()) (term (+ (+ 1 2) 3)))
(test-equal (typecheck (term ·) (term (+ (+ 1 2) 3)))
(term num))
(test-equal (typecheck (term ()) (term (if0 1 (λ ((x num)) x) 3)))
(test-equal (typecheck (term ·) (term (if0 1 (λ (x num) x) 3)))
#f)
(test-equal (typecheck (term ()) (term (if0 1 2 3)))
(test-equal (typecheck (term ·) (term (if0 1 2 3)))
(term num))
(test-equal (typecheck (term ()) (term (λ ((x num)) (x))))
(test-equal (typecheck (term ·) (term (λ (x num) (x 2))))
#f)
(test-equal (typecheck (term ())
(term (λ ((x num))
(λ ((x (num -> num)))
(test-equal (typecheck (term ·)
(term (λ (x num)
(λ (x (num -> num))
(x 0)))))
(term (num -> ((num -> num) -> num))))
(test-equal (typecheck (term ())
(term (λ ((x (num -> num)))
(λ ((x num))
(test-equal (typecheck (term ·)
(term (λ (x (num -> num))
(λ (x num)
(x 0)))))
#f)