add nat tests; start peano nums; nat-ind not working

This commit is contained in:
Stephen Chang 2017-03-13 17:06:25 -04:00
parent fe5adac3db
commit 05f65c13d8
5 changed files with 339 additions and 15 deletions

View File

@ -7,6 +7,7 @@
(define id? identifier?)
(define free-id=? free-identifier=?)
(define fmt format)
(define stx-e syntax-e)
(define (stx-cadr stx) (stx-car (stx-cdr stx)))
(define (stx-caddr stx) (stx-cadr (stx-cdr stx)))

View File

@ -1,8 +1,12 @@
#lang turnstile/lang
; Π λ ≻ ⊢ ≫ ∧ (bidir ⇒ ⇐)
; Π λ ≻ ⊢ ≫ ∧ (bidir ⇒ ⇐)
(provide (rename-out [#%type *]) Π λ #%app ann define define-type-alias)
(provide (rename-out [#%type *])
Π = eq-refl eq-elim
Nat Z S nat-ind
λ #%app ann
define define-type-alias)
#;(begin-for-syntax
(define old-ty= (current-type=?))
@ -14,6 +18,7 @@
(current-typecheck-relation (current-type=?)))
;(define-syntax-category : kind)
(define-base-type Nat)
(define-internal-type-constructor )
(define-internal-binding-type )
;; TODO: how to do Type : Type
@ -37,6 +42,36 @@
[(_ ([x:id : τ_in] ...) τ_out)
#'(~∀ (x ...) (~→ τ_in ... τ_out))]))))
;; equality -------------------------------------------------------------------
(define-internal-type-constructor =)
(define-typed-syntax (= t1 t2)
[ t1 t1- _] [ t2 t2- _]
;; #:do [(printf "t1: ~a\n" (stx->datum #'t1-))
;; (printf "t2: ~a\n" (stx->datum #'t2-))]
; [t1- τ= t2-]
---------------------
[ (=- t1- t2-) #,(expand/df #'#%type)])
(define-typed-syntax (eq-refl e)
[ e e- _]
----------
[ (#%app- void-) (= e- e-)])
(define-typed-syntax (eq-elim t P pt w peq)
[ t t- ty]
; [⊢ P ≫ P- ⇒ _]
; [⊢ pt ≫ pt- ⇒ _]
; [⊢ w ≫ w- ⇒ _]
; [⊢ peq ≫ peq- ⇒ _]
[ P P- ( ty #%type)]
[ pt pt- (P- t-)]
[ w w- ty]
[ peq peq- (= t- w-)]
--------------
[ (#%app- void-) (P- w-)])
;; lambda and #%app -----------------------------------------------------------
;; TODO: add case with expected type + annotations
;; - check that annotations match expected types
(define-typed-syntax λ
@ -49,30 +84,165 @@
---------
[ (λ- (x- ...) e-)]])
;; TODO: do beta on terms?
;; classes for matching number literals
(begin-for-syntax
(define-syntax-class nat
(pattern (~or n:exact-nonnegative-integer (_ n:exact-nonnegative-integer))
#:attr val
#'n))
(define-syntax-class nats
(pattern (n:nat ...) #:attr vals #'(n.val ...)))
; extract list of quoted numbers
(define stx->nat (syntax-parser [n:nat (stx-e #'n.val)]))
(define (stx->nats stx) (stx-map stx->nat stx))
(define (stx+ ns) (apply + (stx->nats ns)))
(define (delta op-stx args)
(syntax-parse op-stx
[(~literal +-) (stx+ args)]
[(~literal zero?-) (apply zero? (stx->nats args))])))
(define-typed-syntax #%app
[(_ e_fn e_arg ...) ; apply lambda
[ e_fn (_ (x ...) e ~!) ( ([X : τ_in] ...) τ_out)]
#:fail-unless (stx-length=? #'[τ_in ...] #'[e_arg ...])
(num-args-fail-msg #'e_fn #'[τ_in ...] #'[e_arg ...])
[ e_arg e_arg- τ_in] ...
#:do[(printf "applying (1) ~a\n" (stx->datum #'e_fn))]
[ e_fn (~and e_fn- (_ (x:id ...) e ~!)) ( ([X : τ_inX] ...) τ_outX)]
#:do[(printf "e_fn-: ~a\n" (stx->datum #'e_fn-))
(printf "args: ~a\n" (stx->datum #'(e_arg ...)))]
#:fail-unless (stx-length=? #'[τ_inX ...] #'[e_arg ...])
(num-args-fail-msg #'e_fn #'[τ_inX ...] #'[e_arg ...])
[ e_arg e_arg- ty-argX] ... ; typechecking args must be fold; do in 2 steps
#:do[(define (ev e)
(syntax-parse e
; [_ #:do[(printf "eval: ~a\n" (stx->datum e))] #:when #f #'(void)]
[(~or _:id
; ((~literal #%plain-lambda) . _)
(~= _ _)
~Nat
((~literal quote) _))
e]
;; handle nums
[((~literal #%plain-app)
(~and op (~or (~literal +-) (~literal zero?-)))
. args:nats)
#`#,(delta #'op #'args.vals)]
[((~literal #%plain-app) (~and f ((~literal #%plain-lambda) . b)) . rst)
(expand/df #`(#%app f . #,(stx-map ev #'rst)))]
[(x ...)
;; #:do[(printf "t before: ~a\n" (typeof e))
;; (printf "t after: ~a\n" (typeof #`#,(stx-map ev #'(x ...))))]
(syntax-property #`#,(stx-map ev #'(x ...)) ': (typeof e))]
[_ e] ; other literals
#;[es (stx-map L #'es)]))]
#:with (τ_in ... τ_out)
(stx-map
(λ (t) (ev (substs #'(e_arg- ...) #'(X ...) t)))
#'(τ_inX ... τ_outX))
#:with (ty-arg ...)
(stx-map
(λ (t) (ev (substs #'(e_arg- ...) #'(X ...) t)))
#'(ty-argX ...))
; #:do[(printf "vars: ~a\n" #'(X ...))]
; #:when (stx-andmap (λ (t1 t2)(displayln (stx->datum t1)) (displayln (stx->datum t2)) (displayln (typecheck? t1 t2)) #;(typecheck? t1 t2)) #'(ty-arg ...) #'(τ_in ...))
;; #:do[(stx-map
;; (λ (tx t) (printf "ty_in inst: \n~a\n~a\n" (stx->datum tx) (stx->datum t)))
;; #'(τ_inX ...) #'(τ_in ...))]
[ e_arg _ τ_in] ...
;; #:do[(printf "res e =\n~a\n" (stx->datum (substs #'(e_arg- ...) #'(x ...) #'e)))
;; (printf "res t = ~a\n" (stx->datum (substs #'(e_arg- ...) #'(X ...) #'τ_out)))]
#:with res-e (let L ([e (substs #'(e_arg- ...) #'(x ...) #'e)]) ; eval
(syntax-parse e
[(~or _:id
((~literal #%plain-lambda) . _)
( ([_ : _] ...) _)
(~= _ _)
~Nat)
e]
;; handle nums
[((~literal #%plain-app)
(~and op (~or (~literal +-) (~literal zero?-)))
. args:nats)
#`#,(delta #'op #'args.vals)]
[((~literal #%plain-app) . rst)
(expand/df #`(#%app . #,(stx-map L #'rst)))]
[_ e] ; other literals
#;[es (stx-map L #'es)]))
;; #:with res-ty (syntax-parse (substs #'(e_arg- ...) #'(X ...) #'τ_out)
;; [((~literal #%plain-app) . rst) (expand/df #'(#%app . rst))]
;; [other-ty #'other-ty])
--------
[ #,(substs #'(e_arg- ...) #'(x ...) #'e)
#,(substs #'(e_arg- ...) #'(X ...) #'τ_out)]]
[ res-e #;#,(substs #'(e_arg- ...) #'(x ...) #'e) τ_out
#;#,(substs #'(e_arg- ...) #'(X ...) #'τ_out)]]
[(_ e_fn e_arg ... ~!) ; apply var
[ e_fn e_fn- ( ([X : τ_in] ...) τ_out)]
#:fail-unless (stx-length=? #'[τ_in ...] #'[e_arg ...])
(num-args-fail-msg #'e_fn #'[τ_in ...] #'[e_arg ...])
[ e_arg e_arg- τ_in] ...
; #:do[(printf "applying (2) ~a\n" (stx->datum #'e_fn))]
[ e_fn e_fn- ty-fn]
; #:do[(printf "e_fn- ty: ~a\n" (stx->datum #'ty-fn))]
[ e_fn _ ( ([X : τ_inX] ...) τ_outX)]
; #:do[(printf "e_fn- no: ~a\n" (stx->datum #'e_fn-))
; (printf "args: ~a\n" (stx->datum #'(e_arg ...)))]
;; #:with e_fn- (syntax-parse #'e_fn*
;; [((~literal #%plain-app) . rst) (expand/df #'(#%app . rst))]
;; [other #'other])
#:fail-unless (stx-length=? #'[τ_inX ...] #'[e_arg ...])
(num-args-fail-msg #'e_fn #'[τ_inX ...] #'[e_arg ...])
[ e_arg e_arg- ty-argX] ... ; typechecking args must be fold; do in 2 steps
#:do[(define (ev e)
(syntax-parse e
; [_ #:do[(printf "eval: ~a\n" (stx->datum e))] #:when #f #'(void)]
[(~or _:id
; ((~literal #%plain-lambda) . _)
(~= _ _)
~Nat
((~literal quote) _))
e]
;; handle nums
[((~literal #%plain-app)
(~and op (~or (~literal +-) (~literal zero?-)))
. args:nats)
#`#,(delta #'op #'args.vals)]
[((~literal #%plain-app) (~and f ((~literal #%plain-lambda) . b)) . rst)
(expand/df #`(#%app f . #,(stx-map ev #'rst)))]
[(x ...)
;; #:do[(printf "t before: ~a\n" (typeof e))
;; (printf "t after: ~a\n" (typeof #`#,(stx-map ev #'(x ...))))]
(syntax-property #`#,(stx-map ev #'(x ...)) ': (typeof e))]
[_ e] ; other literals
#;[es (stx-map L #'es)]))]
#:with (τ_in ... τ_out)
(stx-map
(λ (t) (ev (substs #'(e_arg- ...) #'(X ...) t)))
#'(τ_inX ... τ_outX))
#:with (ty-arg ...)
(stx-map
(λ (t) (ev (substs #'(e_arg- ...) #'(X ...) t)))
#'(ty-argX ...))
;; #:do[(printf "vars: ~a\n" #'(X ...))]
#:when (stx-andmap (λ (e t1 t2)(displayln (stx->datum e))(displayln (stx->datum t1)) (displayln (stx->datum t2)) (displayln (typecheck? t1 t2)) #;(typecheck? t1 t2)) #'(e_arg ...)#'(ty-arg ...) #'(τ_in ...))
;; #:do[(stx-map
;; (λ (tx t) (printf "ty_in inst: \n~a\n~a\n" (stx->datum tx) (stx->datum t)))
;; #'(τ_inX ...) #'(τ_in ...))]
[ e_arg _ τ_in] ...
; #:do[(printf "res e2 =\n~a\n" (stx->datum #'(#%app- e_fn- e_arg- ...)))
; (printf "res t2 = ~a\n" (stx->datum (substs #'(e_arg- ...) #'(X ...) #'τ_out)))]
;; #:with res-e (syntax-parse #'e_fn-
;; [((~literal #%plain-lambda) . _) (expand/df #'(#%app e_fn- e_arg- ...))]
;; [other #'(#%app- e_fn- e_arg- ...)])
--------
[ (#%app- e_fn- e_arg- ...)
#,(substs #'(e_arg- ...) #'(X ...) #'τ_out)]])
[ (#%app- e_fn- e_arg- ...) τ_out
#;#,(expand/df (substs #'(e_arg- ...) #'(X ...) #'τ_out))]])
(define-typed-syntax (ann e (~datum :) τ)
[ e e- τ]
--------
[ e- τ])
(define-typed-syntax (if e1 e2 e3)
[ e1 e1- _]
[ e2 e2- ty]
[ e3 e3- _]
#:do[(displayln #'(e1 e2 e3))]
--------------
[ (#%app- void-) ty])
;; top-level ------------------------------------------------------------------
(define-syntax define-type-alias
(syntax-parser
[(_ alias:id τ);τ:any-type)
@ -111,3 +281,52 @@
(define- f-
(stlc+lit:λ ([x : ty] ...)
(stlc+lit:ann (begin e ...) : ty_out))))]])
;; peano nums -----------------------------------------------------------------
(define-typed-syntax Z
[_:id --- [ 0 Nat]])
(define-typed-syntax (S n)
[ n n- Nat]
-----------
[ (#%app- +- n- 1) Nat])
#;(define-typed-syntax (sub1 n)
[ n n- Nat]
#:do[(displayln #'n-)]
-----------
[ (#%app- -- n- 1) Nat])
;; generalized recursor over natural nums
;; (cases dispatched in #%app)
(define- (nat-ind- P z s n) (#%app- void))
(define-syntax nat-ind
(make-variable-like-transformer
(assign-type
#'nat-ind-
#'(Π ([P : ( Nat #%type)]
[z : (P Z)]
[s : (Π ([k : Nat]) ( (P k) (P (S k))))]
[n : Nat])
(P n)))))
#;(define-type-alias nat-ind
(λ ([P : ( Nat #%type)]
[z : (P Z)]
[s : (Π ([k : Nat]) ( (P k) (P (S k))))]
[n : Nat])
#'(#%app- nat-ind- P z s n)))
#;(define-typed-syntax (nat-ind P z s n)
[ P P- ( Nat #%type)]
; [⊢ b ≫ b- ⇒ _] ; zero
; [⊢ c ≫ c- ⇒ _] ; succ
; [⊢ d ≫ d- ⇒ _]
[ z z- (P- Z)] ; zero
[ s s- (Π ([k : Nat]) ( (P- k) (P- (S k))))] ; succ
[ n n- Nat]
#:with res (if (typecheck? #'n- (expand/df #'Z))
#'z-
#'(s- (nat-ind P- z- s- (sub1 n-))))
----------------
[ res (P- n-)])
; [≻ (P- d-)])

View File

@ -0,0 +1,52 @@
#lang s-exp "../dep.rkt"
(require "rackunit-typechecking.rkt")
; Π → λ ∀ ≻ ⊢ ≫ ⇒
;; examples from Prabhakar's Proust paper
;; Peano nums -----------------------------------------------------------------
(define-type-alias nat-rec
(λ ([C : *])
(λ ([zc : C][sc : ( C C)])
(λ ([n : Nat])
(nat-ind (λ ([x : Nat]) C)
zc
(λ ([x : Nat]) sc)
n)))))
;(check-type nat-rec : (∀ (C) (→ C (→ C C) (→ Nat C))))
(define-type-alias plus
(λ ([n : Nat])
(((nat-rec ( Nat Nat))
(λ ([m : Nat]) m)
(λ ([pm : ( Nat Nat)])
(λ ([x : Nat])
(S (pm x)))))
n)))
(check-type plus : ( Nat ( Nat Nat)))
;(check-type ((plus Z) Z) : Nat -> 0)
;(check-type ((plus (S Z)) (S Z)) : Nat -> 2)
;(check-type ((plus (S Z)) Z) : Nat -> 1)
;; ;; plus zero left
;; (check-type
;; (λ ([n : Nat]) (eq-refl n))
;; : (Π ([n : Nat]) (= ((plus Z) n) n)))
;; (check-type
;; (λ ([n : Nat])
;; (nat-ind (λ ([m : Nat]) (= ((plus m) Z) m))
;; (eq-refl Z)
;; (λ ([k : Nat])
;; (λ ([p : (= ((plus k) Z) k)])
;; (eq-elim ((plus k) Z)
;; (λ ([W : Nat]) (= (S ((plus k) Z)) (S W)))
;; (eq-refl (S ((plus k) Z)))
;; k
;; p)))
;; n))
;; : (Π ([n : Nat]) (= ((plus n) Z) n)))

View File

@ -94,3 +94,54 @@
#:verb-msg
"#%app: type mismatch: expected A, given C") ; TODO: err msg should be B not C?
(check-type and-commutes : ( (A B) ( (And A B) (And B A))))
;; nats -----------------------------------------------------------------------
(define-type-alias nat ( (A) ( A ( A A) A)))
(define-type-alias z (λ ([Ty : *]) (λ ([zero : Ty][succ : ( Ty Ty)]) zero)))
(define-type-alias s (λ ([n : nat])
(λ ([Ty : *])
(λ ([zero : Ty][succ : ( Ty Ty)])
(succ ((n Ty) zero succ))))))
(check-type z : nat)
(check-type s : ( nat nat))
(define-type-alias one (s z))
(define-type-alias two (s (s z)))
(check-type one : nat)
(check-type two : nat)
(define-type-alias plus
(λ ([x : nat][y : nat])
((x nat) y s)))
(check-type plus : ( nat nat nat))
;; equality -------------------------------------------------------------------
(check-type (eq-refl one) : (= one one))
(check-type (eq-refl one) : (= (s z) one))
(check-type (eq-refl two) : (= (s (s z)) two))
(check-type (eq-refl two) : (= (s one) two))
(check-type (eq-refl two) : (= two (s one)))
(check-type (eq-refl two) : (= (s (s z)) (s one)))
(check-type (eq-refl two) : (= (plus one one) two))
(check-not-type (eq-refl two) : (= (plus one one) one))
;; symmetry of =
(check-type
(λ ([A : *][B : *])
(λ ([e : (= A B)])
(eq-elim A (λ ([W : *]) (= W A)) (eq-refl A) B e)))
: ( (A B) ( (= A B) (= B A))))
(check-not-type
(λ ([A : *][B : *])
(λ ([e : (= A B)])
(eq-elim A (λ ([W : *]) (= W A)) (eq-refl A) B e)))
: ( (A B) ( (= A B) (= A B))))
;; transitivity of =
(check-type
(λ ([X : *][Y : *][Z : *])
(λ ([e1 : (= X Y)][e2 : (= Y Z)])
(eq-elim Y (λ ([W : *]) (= X W)) e1 Z e2)))
: ( (A B C) ( (= A B) (= B C) (= A C))))

View File

@ -466,6 +466,7 @@
rule ...+)
#'(define-syntax (rulename stx)
(parameterize ([current-check-relation (current-typecheck-relation)]
[current=? (current-type=?)]
[current-ev (current-type-eval)]
[current-tag (type-key1)])
(syntax-parse/typecheck stx kw-stuff ... rule ...)))]))