Vect and vappend working!

This commit is contained in:
Stephen Chang 2017-08-22 17:17:05 -04:00
parent 98327386ae
commit 47dc16e68a
2 changed files with 349 additions and 175 deletions

View File

@ -48,13 +48,17 @@
(define old-relation (current-typecheck-relation))
(current-typecheck-relation
(lambda (t1 t2)
(when type-eq-debug?
(pretty-print (stx->datum t1))
(pretty-print (stx->datum t2)))
;; assumed #f can only come from (typeof #%type)
;; (so this wont work when interacting with untyped code)
(or (and (false? (syntax-e t1)) (#%type? t2)) ; assign Type : Type
(old-relation t1 t2)))))
(define res
(or (and (false? (syntax-e t1)) (#%type? t2)) ; assign Type : Type
; (and (#%type? t1) (false? (syntax-e t2)))
(old-relation t1 t2)))
(when type-eq-debug?
(pretty-print (stx->datum t1))
(pretty-print (stx->datum t2))
(printf "res: ~a\n" res))
res)))
(define-for-syntax Type ((current-type-eval) #'#%type))
(define-internal-type-constructor ) ; equiv to Π with no uses on rhs
@ -174,8 +178,13 @@
(printf "args: ~a\n" (stx->datum #'args))]
#:when #f #'void]
[(_ f:id (_ matcher) (_ _ . args))
#:do[(when debug-match?
(printf "potential delayed match ~a ~a\n"
(stx->datum #'matcher)
(stx->datum #'args)))]
#:with (_ m/d . _) (local-expand #'(#%app match/delayed 'dont 'care) 'expression null)
#:when (free-identifier=? #'m/d #'f)
#:do[(when debug-match? (printf "matching\n"))]
;; TODO: need to attach type?
#'(matcher . args)]
;; TODO: apply to only lambda args or all args?
@ -183,9 +192,7 @@
#:do[(when debug?
(printf "apping: ~a\n" (stx->datum #'f))
(printf "args\n")
(pretty-print (stx->datum #'(e_arg ...)))
(printf "expected type\n")
(pretty-print (stx->datum (typeof this-syntax))))]
(pretty-print (stx->datum #'(e_arg ...))))]
; #:with (~Π ([X : _] ...) τ_out) (typeof #'f) ; must re-subst in type
;; TODO: need to replace all #%app- in this result with app/eval again
;; and then re-expand
@ -195,16 +202,37 @@
;; TODO: is this assign-type needed only for tests?
;; eg, see id tests in dep2-peano.rkt
#:with ty (typeof this-syntax)
#:do[(when debug?
(define ttt (typeof this-syntax))
(define ttt2 (and ttt
(substs #'(app/eval e_arg ...) #'(r-app x ...) ttt free-identifier=?)))
(define ttt3 (and ttt2
(local-expand ttt2 'expression null)))
(printf "expected type\n")
(pretty-print (stx->datum ttt))
(pretty-print (stx->datum ttt2))
(pretty-print (stx->datum ttt3)))]
#:with e-inst (substs #'(app/eval e_arg ...) #'(r-app x ...) #'e free-identifier=?)
;; some apps may not have type (eg in internal reps)
#:with e+ (if (syntax-e #'ty) (assign-type #'e-inst #'ty) #'e-inst)
#:with e+ (if (syntax-e #'ty)
(assign-type
#'e-inst
(local-expand
; (substs #'(app/eval e_arg ...) #'(r-app x ...) #'ty free-identifier=?)
;; TODO: this is needed, which means there are some uneval'ed matches
;; but is this the right place?
;; eg, it wasnt waiting on any arg
;; so that mean it could have been evaled but wasnt at some point
(substs #'(app/eval) #'(r-app) #'ty free-identifier=?)
'expression null))
#'e-inst)
#:do[(when debug?
(displayln "res:--------------------")
(pretty-print (stx->datum #'e+))
;; (displayln "actual type:")
;; (pretty-print (stx->datum (typeof #'e+)))
;; (displayln "new type:")
;; (pretty-print (stx->datum (substs #'(e_arg ...) #'(X ...) (typeof #'e+))))
(displayln "new type:")
(pretty-print (stx->datum (typeof #'e+)))
;; (displayln "res expanded:------------------------")
;; (pretty-print
;; (stx->datum (local-expand (substs #'(e_arg ...) #'(x ...) #'e) 'expression null)))
@ -457,112 +485,118 @@
(struct TmpTy2 ())
(define-syntax mTmpTy (syntax-parser [(_ . args) #'(#%app TmpTy . args)]))
(define-typed-syntax define-datatype
;; kind is an id --------------------
[(_ Name (~datum :) kind:id [C:id (~datum :) TY #;(~and TY (ar tyin ... tyout))] ...)
; need to expand `TY` but `Name` is still unbound so use tmp id
#:with (TY* ...) (subst #'TmpTy #'Name #'(TY ...))
[ TY* TY- #%type] ...
;; kind is an id ------------------------------------------------------------
;; - ie, no params or indices
[(_ Name (~datum :) kind:id [C:id (~datum :) CTY] ...)
; need to expand `CTY` to find recur args,
; but `Name` is still unbound so swap in a tmp id `TmpTy`
#:with (CTY/tmp ...) (subst #'TmpTy #'Name #'(CTY ...))
[ CTY/tmp CTY/tmp- #%type] ...
#:with (_ TmpTy+) (local-expand #'(TmpTy) 'expression null)
;; TODO: ignoring X ... for now
;; un-subst TmpTy for Name in expanded CTY
;; TODO: replace TmpTy in origs of τ_in ... τ_out
#:with (( ([X : τ_in] ...) τ_out) ...)
(subst #'Name #'TmpTy+ #'(TY- ...) free-id=?)
#:with (C* ...) (generate-temporaries #'(C ...))
#:with (( ([x : τ_in] ...) τ_out) ...)
(subst #'Name #'TmpTy+ #'(CTY/tmp- ...) free-id=?)
#:with (C/internal ...) (generate-temporaries #'(C ...))
#:with (Ccase ...) (generate-temporaries #'(C ...))
#:with (C- ...) (generate-temporaries #'(C ...))
;; Can I just use X instead of fld?
#:with ((fld ...) ...) (stx-map generate-temporaries #'((τ_in ...) ...))
#:with ((recur-fld ...) ...) (stx-map
(lambda (fs ts)
(filter
(lambda (x) x) ; filter out #f
(stx-map
(lambda (f t) (and (free-id=? t #'Name) f)) ; returns f or #f
fs ts)))
#'((fld ...) ...)
#'((τ_in ...) ...))
#:with ((fld- ...) ...) (stx-map generate-temporaries #'((τ_in ...) ...))
#:with (Ccase- ...) (generate-temporaries #'(C ...))
#:with ((recur-x ...) ...) (stx-map
(lambda (xs ts)
(filter
(lambda (x) x) ; filter out #f
(stx-map
(lambda (x t) (and (free-id=? t #'Name) x)) ; returns x or #f
xs ts)))
#'((x ...) ...)
#'((τ_in ...) ...))
#:with elim-Name (format-id #'Name "elim-~a" #'Name)
#:with match-Name (format-id #'Name "match-~a" #'Name)
; #:with match-Name/delayed (format-id #'Name "match-~a/delayed" #'Name)
#:with Name/internal (generate-temporary #'Name)
--------
[ (begin-
(define-base-type Name)
(struct C* (fld ...) #:transparent) ...
(define C (unsafe-assign-type C* : TY)) ...
#;(define-typed-syntax C
[:id --- [ C* TY]]
[(_ fld ...)
[ fld fld- τ_in] ...
--------
[ (C* fld- ...) τ_out]])
(define-typed-syntax (elim-Name x P C* ...)
[ x x- Name]
(struct Name/internal ())
(define-typed-syntax Name
[_:id --- [ (Name/internal) #%type]])
;(define-base-type Name) ; cant use this bc it tries to attach type with '::
(struct C/internal (x ...) #:transparent) ...
(define C (unsafe-assign-type C/internal : CTY)) ...
(define-typed-syntax (elim-Name v P Ccase ...)
[ v v- Name]
[ P P- ( Name #%type)] ; prop / motive
; [⊢ z ≫ z- ⇐ (app P- Zero)] ; zero
; [⊢ C ≫ C- ⇐ (Π ([k : Nat]) (→ (app P- k) (app P- (Succ k))))] ; succ
;; TODO: the (app P- fld) ... is wrong, should only include recur args
;; for now, each case consumes the number of args for each C,
;; and then an IH for each arg
;; each C consumes 3 sets of args
;; 1) args of the tycon
;; 2) args of the con
;; 3) IH for each recursive arg
;; TODO: get rid of this use of τ_in
;; - then I wont have to un-subst above
[ C* C- (Π ([fld : τ_in] ...) ( (app P- recur-fld) ... (app P- (app C fld ...))))] ...
[ Ccase Ccase- (Π ([x : τ_in] ...)
( (app P- recur-x) ...
(app P- (app C x ...))))] ...
-----------
[ (match-Name x- P- C- ...) (app P- x-)])
; (struct match-Name/delayed (m))
[ (match-Name v- P- Ccase- ...) (app P- v-)])
(define-syntax match-Name
(syntax-parser
#;[(_ . args)
#:do[(printf "trying to match:\n~a\n" (stx->datum #'args))]
#:when #f #'(void)]
[(_ n P Ccase ...)
(syntax-parse #'n
[((~literal #%plain-app) C-:id fld ...)
;; TODO: check C- matches actual C
;; for now, it's just an arity match
#'(app/eval (app/eval Ccase fld ...) (match-Name fld P Ccase ...) ...)] ...
[_ #'(#%app match/delayed 'match-Name (void n P Ccase ...))])]))
[(_ v P Ccase ...)
; must local expand since v might be reflected
(syntax-parse (local-expand #'v 'expression null)
; do eval
[((~literal #%plain-app) C-:id x ...)
#:with (_ C+ . _) (local-expand #'(C 'x ...) 'expression null)
#:when (free-identifier=? #'C- #'C+)
#'(app/eval (app/eval Ccase x ...) (match-Name x P Ccase ...) ...)]
...
; else generated a delayed term
[_ #'(#%app match/delayed 'match-Name (void v P Ccase ...))])]))
)]]
;; --------------------------------------------------------------------------
;; kind is a fn; all cases in elim-Name must consume tycon args -------------
;; --------------------------------------------------------------------------
[(_ Name (~datum :) k [C:id (~datum :) TY #;(~and TY (ar tyin ... tyout))] ...)
[ k ( ([A : k_in] ...) k_out) #%type]
[(_ Name (~datum :) k [C:id (~datum :) CTY] ...)
;; params and indices are separate here, to distinguish them,
;; but are combined in other places like CTY
[ k ( ([A : kA] ...) ; params
( ([i : ki] ...) ; indices
k_out)) #%type]
#:with (A- ...) (generate-temporaries #'(A ...))
#:with (i- ...) (generate-temporaries #'(i ...))
#:with (j ...) (generate-temporaries #'(i ...))
#:with (B ...) (generate-temporaries #'(A ...))
;; need to multiply A patvars to use in def of C ...
#:with ((CA ...) ...) (stx-map (lambda _ (generate-temporaries #'(A ...))) #'(C ...))
#:with ((CAtmp ...) ...) (stx-map (lambda _ (generate-temporaries #'(A ...))) #'(C ...))
; actually dup (A ...) C times
#:with ((A* ...) ...) (stx-map (lambda _ #'(A ...)) #'(C ...))
#:with ((Ci ...) ...) (stx-map (lambda _ (generate-temporaries #'(i ...))) #'(C ...))
#:with ((Cj ...) ...) (stx-map (lambda _ (generate-temporaries #'(i ...))) #'(C ...))
; CB is just reference to CA
#:with ((CB ...) ...) (stx-map (lambda _ (generate-temporaries #'(A ...))) #'(C ...))
#:with ((Ck ...) ...) (stx-map (lambda _ (generate-temporaries #'(A ...))) #'(C ...))
; need to expand `TY` but `Name` is still unbound so use tmp id
#:with (TY* ...) (subst #'mTmpTy #'Name #'(TY ...))
[ TY* TY- #%type] ...
#:with (_ TmpTy+) (local-expand #'(TmpTy) 'expression null)
;; ;; TODO: ignoring X ... for now
#:with ((CkA ...) ...) (stx-map (lambda _ (generate-temporaries #'(A ...))) #'(C ...))
#:with ((Cki ...) ...) (stx-map (lambda _ (generate-temporaries #'(ki ...))) #'(C ...))
; need to expand `CTY` but `Name` is still unbound so use tmp id
#:with (CTY/tmp ...) (subst #'mTmpTy #'Name #'(CTY ...))
[ CTY/tmp CTY/tmp- #%type] ...
#:with (_ TmpTy+) (local-expand #'(mTmpTy) 'expression null)
;; ;; TODO: replace TmpTy in origs of τ_in ... τ_out
;; #:with ((~Π ([X : τ_in] ...) τ_out) ...)
;; (subst #'Name #'TmpTy+ #'(TY- ...) free-id=?)
;; TODO: how to un-subst TmpTy (which is now a constructor)?
;; for now, dont use these τ_in/τ_out; just use for arity
;; instead, re-expand in generated macro
;; - first Π is tycon args
;; - for now, dont use these τ_in/τ_out; just use for arity
;; - instead, re-expand in generated macro
;; - 1st Π is tycon params and indices
;; - 2nd Π is constructor args
#:with (( ([_ : _] ...) ( ([X : τ_in/tmp] ...) τ_out/tmp)) ...)
#'(TY- ...)
#:with (C* ...) (generate-temporaries #'(C ...))
#'(CTY/tmp- ...)
#:with (C/internal ...) (generate-temporaries #'(C ...))
#:with (Cty ...) (generate-temporaries #'(C ...))
#:with (C** ...) (generate-temporaries #'(C ...))
#:with (Cty2 ...) (generate-temporaries #'(C ...))
#:with (Ccase ...) (generate-temporaries #'(C ...))
#:with (Ccase- ...) (generate-temporaries #'(C ...))
#:with (C- ...) (generate-temporaries #'(C ...))
;; TODO: Can I just use X instead of fld?
;; - but I need τ_in to find recurs
#:with ((fld ...) ...) (stx-map generate-temporaries #'((X ...) ...))
#:with ((τ_in ...) ...) (stx-map generate-temporaries #'((τ_in/tmp ...) ...))
#:with ((τ_in/CA ...) ...) (stx-map generate-temporaries #'((τ_in/tmp ...) ...))
#:with ((τ_in/X ...) ...) (stx-map generate-temporaries #'((τ_in/tmp ...) ...))
#:with (τ_out ...) (generate-temporaries #'(τ_out/tmp ...))
;; each (recur-fld ...) is subset of (fld ...) that are recur args
;; - ie, they are not fresh ids
#:with ((recur-fld ...) ...) (stx-map
(lambda (fs ts)
(filter
@ -574,15 +608,21 @@
[((~literal #%plain-app) tmp . _)
(free-id=? #'tmp #'TmpTy+)]
[_ #f])
f)
#;(and (free-id=? t #'Name) f)) ; returns f or #f
f)) ; returns f or #f
fs ts)))
#'((fld ...) ...)
#'((τ_in/tmp ...) ...))
#:with ((CArecur ...) ...) (stx-map
(lambda (cas recurs) cas)
#'((CA ...) ...)
#'((recur-fld ...) ...))
#:with (((CAr ...) ...) ...) (stx-map
(lambda (cas recurs)
(stx-map (lambda (r) cas) recurs))
#'((CA ...) ...)
#'((recur-fld ...) ...))
; dup Ci for each recur
#:with (((Cir ...) ...) ...) (stx-map
(lambda (cis recurs)
(stx-map (lambda (r) cis) recurs))
#'((Ci ...) ...)
#'((recur-fld ...) ...))
#:with ((fld- ...) ...) (stx-map generate-temporaries #'((X ...) ...))
#:with Name- (mk-- #'Name)
#:with Name-patexpand (mk-~ #'Name)
@ -592,24 +632,25 @@
--------
[ (begin-
(define-internal-type-constructor Name)
(define-typed-syntax (Name A ...)
[ A A- k_in] ...
(define-typed-syntax (Name A ... i ...)
[ A A- kA] ...
[ i i- ki] ...
----------
[ (Name- A- ...) k_out])
(struct C* (fld ...) #:transparent) ...
(define C (unsafe-assign-type (lambda (A ...) C*) : TY)) ...
(define-typed-syntax (elim-Name x P C** ...)
#:with (( ([CA : Ck] ...) ( ([_ : τ_in] ...) (Name-patexpand CB ...))) ...)
(stx-map (current-type-eval) #'(TY ...))
;; #:with ((τ_in ...) ...)
;; (stx-map (lambda (tins cas) (substs #'(A- ...) cas tins))
;; #'((τ_in/X ...) ...)
;; #'((CA ...) ...))
[ x x- (Name-patexpand B ...)]
; [⊢ x ≫ x- ⇐ (Name A ...)]
[ P P- (Π ([A : k_in] ...) ( (Name A ...) #%type))] ; prop / motive
; [⊢ z ≫ z- ⇐ (app P- Zero)] ; zero
; [⊢ C ≫ C- ⇐ (Π ([k : Nat]) (→ (app P- k) (app P- (Succ k))))] ; succ
[ (Name- A- ... i- ...) k_out])
(struct C/internal (fld ...) #:transparent) ...
(define C (unsafe-assign-type (lambda (A ... i ...) C/internal) : CTY)) ...
(define-typed-syntax (elim-Name v P Ccase ...)
#:with (( ([CA : _] ... ; dont care about params, since we will immediately inst with A
[Ci : Cki] ...)
( ([_ : τ_in/CA] ...)
(Name-patexpand CB ... Cj ...)))
...)
(stx-map (current-type-eval) #'(CTY ...))
[ v v- (Name-patexpand A ... i ...)]
#:with ((τ_in ...) ...) (stx-map (lambda (tins cas) (substs #'(A ...) cas tins))
#'((τ_in/CA ...) ...)
#'((CA ...) ...))
[ P P- (Π ([j : ki] ...) ( (Name A ... j ...) #%type))] ; prop / motive
;; TODO: the (app P- fld) ... is wrong, should only include recur args
;; for now, each case consumes the number of args for each C,
;; and then an IH for each arg
@ -617,50 +658,44 @@
;; 1) args of the tycon
;; 2) args of the con
;; 3) IH for each recursive arg
;; manually construct Cty, bc `syntax` isnt smart enough to figure out ellipses
;; #:do[(printf "elim \n")
;; (pretty-print (stx->datum this-syntax))]
#:with (Cty ...)
(stx-map
(lambda (CA-Cks CAs CBs #;Cks fld-tins flds #;tins rflds c)
#`(Π #,CA-Cks
(Π #,fld-tins
( #,@(stx-map
(lambda (rf) #`(app (app P- #,@CAs) #,rf))
rflds)
(app (app P- #,@CBs) (app (app #,c #,@CAs) #,@flds))))))
#'(([CA : Ck] ...) ...)
#'((CA ...) ...)
#'((CB ...) ...)
; #'((Ck ...) ...)
#'(([fld : τ_in] ...) ...)
#'((fld ...) ...)
; #'((τ_in ...) ...)
#'((recur-fld ...) ...)
#'(C ...))
;; #:do[(stx-map (lambda (t) (pretty-print (stx->datum t))((current-type-eval) t)) #'(Cty ...))]
;; #:do[(pretty-print (stx->datum #'(Cty ...)))]
[ C** C- Cty] ...
;; [⊢ C* ≫ C- ⇐ (Π ([CA : Ck] ...)
;; (Π ([fld : τ_in] ...)
;; (→ (app (app P- CA ...) recur-fld) ... ; IHs
;; (app (app P- CA ...) (app (app C CA ...) fld ...)))))] ...
;; #:with (Cty ...)
;; (stx-map
;; (lambda (CA-Cks CAs CBs #;Cks fld-tins flds #;tins rflds c)
;; #`(Π #,CA-Cks
;; (Π #,fld-tins
;; (→ #,@(stx-map
;; (lambda (rf) #`(app (app P- #,@CAs) #,rf))
;; rflds)
;; (app (app P- #,@CBs) (app (app #,c #,@CAs) #,@flds))))))
;; #'(([CA : Ck] ...) ...)
;; #'((CA ...) ...)
;; #'((CB ...) ...)
;; ; #'((Ck ...) ...)
;; #'(([fld : τ_in] ...) ...)
;; #'((fld ...) ...)
;; ; #'((τ_in ...) ...)
;; #'((recur-fld ...) ...)
;; #'(C ...))
[ Ccase Ccase- (Π ([Ci : Cki] ...)
(Π ([fld : τ_in] ...)
( (app (app P- Cir ...) recur-fld) ... ; IHs
(app (app P- Cj ...)
(app (app C A* ... Ci ...) fld ...)))))] ...
-----------
[ (match-Name x- P- C- ...) (app (app P- B ...) x-)])
; (struct match-Name/delayed (m))
[ (match-Name v- P- Ccase- ...) (app (app P- i ...) v-)])
(define-syntax match-Name
(syntax-parser
#;[(_ . args)
#:do[(printf "trying to match:\n~a\n" (stx->datum #'args))]
#:when #f #'(void)]
[(_ n P Ccase ...)
(syntax-parse #'n
[((~literal #%plain-app) ((~literal #%plain-app) C-:id CA ...) fld ...)
(syntax-parse (local-expand #'n 'expression null)
[((~literal #%plain-app) ((~literal #%plain-app) CC:id CA ... Ci ...) fld ...)
#:with (_ CC- . _) (local-expand #'(C 'CA ...) 'expression null)
#:when (free-identifier=? #'CC #'CC-)
; #:do[(printf "matched ~a\n" #'C-)]
;; TODO: check C- matches actual C
;; for now, it's just an arity match
#'(app/eval (app/eval (app/eval Ccase CA ...) fld ...) (match-Name recur-fld P Ccase ...) ...)] ...
#'(app/eval (app/eval (app/eval Ccase Ci ...) fld ...) (match-Name recur-fld P Ccase ...) ...)] ...
[_ #'(#%app match/delayed 'match-Name (void n P Ccase ...))])]))
)]])
;; ;; #:with res (if (typecheck? #'n- (expand/df #'Z))
@ -764,7 +799,7 @@
;; [s : (Π ([k : Nat]) (→ (P k) (P (S k))))]
;; [n : Nat])
;; #'(#%app- nat-ind- P z s n)))
(struct match/delayed (name args))
(struct match/delayed (name args) #:transparent)
;; #;(define-syntax match/eval
;; (syntax-parser
;; [(_ n zc sc) #:do[(printf "matching: ~a\n" (stx->datum #'n))] #:when #f #'(void)]

View File

@ -7,7 +7,12 @@
[Z : ( Nat)]
[S : ( Nat Nat)])
(define-datatype List : ( * *)
;; some basic tests
(check-type Nat : *)
;; this test wont work if define-datatype uses define-base-type
(check-type (λ ([x : Nat]) Nat) : ( Nat *))
(define-datatype List : ( * ( *))
[null : ( (A) ( (List A)))]
[cons : ( (A) ( A (List A) (List A)))])
@ -21,10 +26,10 @@
;; length 0
(check-type
(elim-List ((null Nat))
(λ ([A : *]) (λ ([l : (List A)]) Nat))
(λ ([A : *]) (λ () (λ () (Z))))
(λ ([A : *])
(λ ([x : A][xs : (List A)])
(λ () (λ ([l : (List Nat)]) Nat))
(λ () (λ () (λ () (Z))))
(λ ()
(λ ([x : Nat][xs : (List Nat)])
(λ ([IH : Nat])
(S IH)))))
: Nat
@ -33,10 +38,10 @@
;; length 1
(check-type
(elim-List ((cons Nat) (Z) ((null Nat)))
(λ ([A : *]) (λ ([l : (List A)]) Nat))
(λ ([A : *]) (λ () (λ () (Z))))
(λ ([A : *])
(λ ([x : A][xs : (List A)])
(λ () (λ ([l : (List Nat)]) Nat))
(λ () (λ () (λ () (Z))))
(λ ()
(λ ([x : Nat][xs : (List Nat)])
(λ ([IH : Nat])
(S IH)))))
: Nat
@ -45,30 +50,64 @@
;; length 2
(check-type
(elim-List ((cons Nat) (S (Z)) ((cons Nat) (Z) ((null Nat))))
(λ ([A : *]) (λ ([l : (List A)]) Nat))
(λ ([A : *]) (λ () (λ () (Z))))
(λ ([A : *])
(λ ([x : A][xs : (List A)])
(λ () (λ ([l : (List Nat)]) Nat))
(λ () (λ () (λ () (Z))))
(λ ()
(λ ([x : Nat][xs : (List Nat)])
(λ ([IH : Nat])
(S IH)))))
: Nat
-> (S (S (Z))))
(define-type-alias len
(define-type-alias len/Nat
(λ ([lst : (List Nat)])
(elim-List lst
(λ ([A : *]) (λ ([l : (List A)]) Nat))
(λ ([A : *]) (λ () (λ () (Z))))
(λ ([A : *])
(λ ([x : A][xs : (List A)])
(λ () (λ ([l : (List Nat)]) Nat))
(λ () (λ () (λ () (Z))))
(λ ()
(λ ([x : Nat][xs : (List Nat)])
(λ ([IH : Nat])
(S IH)))))))
(check-type (len ((null Nat))) : Nat -> (Z))
(check-type (len ((cons Nat) (Z) ((null Nat)))) : Nat -> (S (Z)))
(check-type (len/Nat ((null Nat))) : Nat -> (Z))
(check-type (len/Nat ((cons Nat) (Z) ((null Nat)))) : Nat -> (S (Z)))
;; Vect: "lists" parameterized over length --------------------
(define-datatype Vect : ( * Nat *)
(define-type-alias len
(λ ([A : *])
(λ ([lst : (List A)])
(elim-List lst
(λ () (λ ([l : (List A)]) Nat))
(λ () (λ () (λ () (Z))))
(λ ()
(λ ([x : A][xs : (List A)])
(λ ([IH : Nat])
(S IH))))))))
(check-type (len Nat) : ( (List Nat) Nat))
(check-type ((len Nat) ((null Nat))) : Nat -> (Z))
(check-type ((len Nat) ((cons Nat) (Z) ((null Nat)))) : Nat -> (S (Z)))
;; test that elim matches on constructor name, and not arity
(define-datatype Test : *
[A : ( Test)]
[B : ( Test)])
(check-type
(elim-Test (A)
(λ ([x : Test]) Nat)
(λ () (λ () (Z)))
(λ () (λ () (S (Z)))))
: Nat -> (Z))
;; should match second branch, but just arity-checking would match 1st
(check-type
(elim-Test (B)
(λ ([x : Test]) Nat)
(λ () (λ () (Z)))
(λ () (λ () (S (Z)))))
: Nat -> (S (Z)))
;; Vect: indexed "lists" parameterized over length --------------------
(define-datatype Vect : ( * ( Nat *))
[nil : (Π ([A : *][k : Nat]) ( (Vect A (Z))))]
[cns : (Π ([A : *][k : Nat]) ( A (Vect A k) (Vect A (S k))))])
@ -88,35 +127,135 @@
(define-type-alias mtNatVec ((nil Nat (Z))))
(check-type mtNatVec : (Vect Nat (Z)))
;; nil must be applied again (bc it's a constructor of 0 args)
(check-not-type (nil Nat (S (Z))) : (Vect Nat (S (Z))))
;; length
(check-type
(elim-Vect ((nil Nat (Z)))
(λ ([A : *][k : Nat]) (λ ([v : (Vect A k)]) Nat))
(λ ([A : *][k : Nat]) (λ () (λ () (Z))))
(λ ([A : *][k : Nat])
(λ ([x : A][xs : (Vect A k)])
(λ ([k : Nat]) (λ ([v : (Vect Nat k)]) Nat))
(λ ([k : Nat]) (λ () (λ () (Z))))
(λ ([k : Nat])
(λ ([x : Nat][xs : (Vect Nat k)])
(λ ([IH : Nat])
(S IH)))))
: Nat -> (Z))
(check-type
(elim-Vect ((cns Nat (Z)) (Z) ((nil Nat (Z))))
(λ ([A : *][k : Nat]) (λ ([v : (Vect A k)]) Nat))
(λ ([A : *][k : Nat]) (λ () (λ () (Z))))
(λ ([A : *][k : Nat])
(λ ([x : A][xs : (Vect A k)])
(λ ([k : Nat]) (λ ([v : (Vect Nat k)]) Nat))
(λ ([k : Nat]) (λ () (λ () (Z))))
(λ ([k : Nat])
(λ ([x : Nat][xs : (Vect Nat k)])
(λ ([IH : Nat])
(S IH)))))
: Nat -> (S (Z)))
(check-type
(elim-Vect ((cns Nat (S (Z))) (Z) ((cns Nat (Z)) (Z) ((nil Nat (Z)))))
(λ ([A : *][k : Nat]) (λ ([v : (Vect A k)]) Nat))
(λ ([A : *][k : Nat]) (λ () (λ () (Z))))
(λ ([A : *][k : Nat])
(λ ([x : A][xs : (Vect A k)])
(λ ([k : Nat]) (λ ([v : (Vect Nat k)]) Nat))
(λ ([k : Nat]) (λ () (λ () (Z))))
(λ ([k : Nat])
(λ ([x : Nat][xs : (Vect Nat k)])
(λ ([IH : Nat])
(S IH)))))
: Nat -> (S (S (Z))))
(define-type-alias plus
(λ ([n : Nat][m : Nat])
(elim-Nat n
(λ ([k : Nat]) Nat)
(λ () (λ () m))
(λ ([k : Nat]) (λ ([IH : Nat]) (S IH))))))
(check-type plus : ( Nat Nat Nat))
(check-type (plus (Z) (S (S (Z)))) : Nat -> (S (S (Z))))
(check-type (plus (S (S (Z))) (Z)) : Nat -> (S (S (Z))))
(check-type (plus (S (S (Z))) (S (S (S (Z)))))
: Nat -> (S (S (S (S (S (Z)))))))
;; vappend
(check-type
(elim-Vect
((nil Nat (Z)))
(λ ([k : Nat])
(λ ([v : (Vect Nat k)])
(Vect Nat k)))
(λ ([k : Nat]) (λ () (λ () ((nil Nat (Z))))))
(λ ([k : Nat])
(λ ([x : Nat][v : (Vect Nat k)])
(λ ([IH : (Vect Nat k)])
((cns Nat k) x IH)))))
: (Vect Nat (Z))
-> ((nil Nat (Z))))
(define-type-alias vappend
(λ ([A : *])
(λ ([n : Nat][m : Nat])
(λ ([xs : (Vect A n)][ys : (Vect A m)])
(elim-Vect
xs
(λ ([k : Nat])
(λ ([v : (Vect A k)])
(Vect A (plus k m))))
(λ ([k : Nat]) (λ () (λ () ys)))
(λ ([k : Nat])
(λ ([x : A][v : (Vect A k)])
(λ ([IH : (Vect A (plus k m))])
((cns A (plus k m)) x IH)))))))))
(check-type
vappend
: ( (B)
(Π ([n : Nat][m : Nat])
( (Vect B n) (Vect B m) (Vect B (plus n m))))))
(check-type
(vappend Nat)
: (Π ([n : Nat][m : Nat])
( (Vect Nat n) (Vect Nat m) (Vect Nat (plus n m)))))
(check-type
((vappend Nat) (Z) (Z))
: ( (Vect Nat (Z)) (Vect Nat (Z)) (Vect Nat (Z))))
;; append nil + nil
(check-type
(((vappend Nat) (Z) (Z)) ((nil Nat (Z))) ((nil Nat (Z))))
: (Vect Nat (Z))
-> ((nil Nat (Z))))
;; append 1 + 0
(check-type
(((vappend Nat) (S (Z)) (Z)) ((cns Nat (Z)) (Z) ((nil Nat (Z)))) ((nil Nat (Z))))
: (Vect Nat (S (Z)))
-> ((cns Nat (Z)) (Z) ((nil Nat (Z)))))
;; m and n flipped
(typecheck-fail
(((vappend Nat) (S (Z)) (Z)) ((nil Nat (Z))) ((cns Nat (Z)) (Z) ((nil Nat (Z))))))
(typecheck-fail
(((vappend Nat) (Z) (S (Z))) ((cns Nat (Z)) (Z) ((nil Nat (Z)))) ((nil Nat (Z)))))
;; append 1 + 1
(check-type
(((vappend Nat) (S (Z)) (S (Z))) ((cns Nat (Z)) (Z) ((nil Nat (Z)))) ((cns Nat (Z)) (Z) ((nil Nat (Z)))))
: (Vect Nat (S (S (Z))))
-> ((cns Nat (S (Z))) (Z) ((cns Nat (Z)) (Z) ((nil Nat (Z))))))
;; append 1 + 2
(check-type
(((vappend Nat) (S (Z)) (S (S (Z))))
((cns Nat (Z)) (Z) ((nil Nat (Z))))
((cns Nat (S (Z))) (Z) ((cns Nat (Z)) (Z) ((nil Nat (Z))))))
: (Vect Nat (S (S (S (Z)))))
-> ((cns Nat (S (S (Z)))) (Z) ((cns Nat (S (Z))) (Z) ((cns Nat (Z)) (Z) ((nil Nat (Z)))))))
;; append 2 + 1
(check-type
(((vappend Nat) (S (S (Z))) (S (Z)))
((cns Nat (S (Z))) (Z) ((cns Nat (Z)) (Z) ((nil Nat (Z)))))
((cns Nat (Z)) (Z) ((nil Nat (Z)))))
: (Vect Nat (S (S (S (Z)))))
-> ((cns Nat (S (S (Z)))) (Z) ((cns Nat (S (Z))) (Z) ((cns Nat (Z)) (Z) ((nil Nat (Z)))))))