diff --git a/turnstile/examples/dep-ind-fixed.rkt b/turnstile/examples/dep-ind-fixed.rkt
new file mode 100644
index 0000000..e5cd68c
--- /dev/null
+++ b/turnstile/examples/dep-ind-fixed.rkt
@@ -0,0 +1,717 @@
+#lang turnstile/lang
+
+; a basic dependently-typed calculus
+; - with inductive datatypes
+
+; created this new file to avoid breaking anything using dep-ind.rkt
+
+; this file is mostly same as dep-ind.rkt but define-datatype has some fixes:
+; 1) params and indices must be applied separately
+;   - for constructor (but not type constructor)
+; 2) allows indices to depend on param
+; 3) indices were not being inst with params
+; 4) arg refs were using x instead of Cx from new expansion
+; TODO: re-compute recur-x, ie recur-Cx
+
+; Π  λ ≻ ⊢ ≫ → ∧ (bidir ⇒ ⇐) τ⊑
+
+(provide Type (rename-out [Type *])
+         Π → ∀
+         = eq-refl eq-elim
+         λ (rename-out [app #%app]) ann
+         define-datatype define define-type-alias
+)
+
+;; TODO:
+;; - map #%datum to S and Z
+;; - rename define-type-alias to define
+;; - add "assistant" part
+;; - provide match and match/lambda so nat-ind can be fn
+;;   - eg see https://gist.github.com/AndrasKovacs/6769513
+;; - add dependent existential
+;; - remove debugging code?
+
+;; set (Type n) : (Type n+1)
+;; Type = (Type 0)
+(define-internal-type-constructor Type)
+(define-typed-syntax Type
+  [:id ≫ --- [≻ (Type 0)]]
+  [(_ n:exact-nonnegative-integer) ≫
+   #:with n+1 (+ (syntax-e #'n) 1)
+  -------------
+  [≻ #,(syntax-property
+        (syntax-property 
+         #'(Type- 'n) ':
+         (syntax-property
+          #'(Type- 'n+1)
+          'orig
+          (list #'(Type n+1))))
+        'orig
+        (list #'(Type n)))]])
+
+(begin-for-syntax
+  (define debug? #f)
+  (define type-eq-debug? #f)
+  (define debug-match? #f)
+
+  ;; TODO: fix `type` stx class
+  ;; current-type and type stx class not working
+  ;; for case where var has type that is previous var
+  ;; that is not yet in tyenv
+  ;; eg in (Π ([A : *][a : A]) ...)
+  ;; expansion of 2nd type A will fail with unbound id err
+  ;;
+  ;; attempt 2
+  ;; (define old-type? (current-type?))
+  ;; (current-type?
+  ;;  (lambda (t)
+  ;;    (printf "t = ~a\n" (stx->datum t))
+  ;;    (printf "ty = ~a\n" (stx->datum (typeof t)))
+  ;;    (or (Type? (typeof t))
+  ;;        (syntax-parse (typeof t)
+  ;;          [((~literal Type-) n:exact-nonnegative-integer) #t]
+  ;;          [_ #f]))))
+  ;; attempt 1
+  ;; (define old-type? (current-type?))
+  ;; (current-type?
+  ;;  (lambda (t) (or (#%type? t) (old-type? t))))
+
+
+  (define old-relation (current-typecheck-relation))
+  (current-typecheck-relation
+   (lambda (t1 t2)
+     (define res
+       ;; expand (Type n) if unexpanded
+       (or (syntax-parse t1
+             [((~literal Type-) n)
+              (typecheck? ((current-type-eval) t1) t2)]
+             [_ #f])
+           (old-relation t1 t2)))
+     (when type-eq-debug?
+       (pretty-print (stx->datum t1))
+       (pretty-print (stx->datum t2))
+       (printf "res: ~a\n" res))
+     res))
+  ;; used to attach type after app/eval
+  ;; but not all apps will have types, eg
+  ;; - internal type representation
+  ;; - intermediate elim terms
+  (define (maybe-assign-type e t)
+    (if (syntax-e t) (assign-type e t) e)))
+
+(define-internal-type-constructor →) ; equiv to Π with no uses on rhs
+(define-internal-binding-type ∀)     ; equiv to Π with Type for all params
+
+;; Π expands into combination of internal →- and ∀-
+;; uses "let*" syntax where X_i is in scope for τ_i+1 ...
+;; TODO: add tests to check this
+(define-typed-syntax (Π ([X:id : τ_in] ...) τ_out) ≫
+  [[X ≫ X- : τ_in] ... ⊢ [τ_out ≫ τ_out- ⇒ tyoutty]
+                         [τ_in  ≫ τ_in-  ⇒ tyinty] ...]
+  ;; check that types have type (Type _)
+  ;; must re-expand since (Type n) will have type unexpanded (Type n+1)
+  #:with ((~Type _) ...) (stx-map (current-type-eval) #'(tyoutty tyinty ...))
+  -------
+  [⊢ (∀- (X- ...) (→- τ_in- ... τ_out-)) ⇒ Type]
+  #;[⊢ #,#`(∀- (X- ...)
+             #,(assign-type
+                #'(→- τ_in- ... τ_out-)
+                #'#%type)) ⇒ #%type])
+
+;; abbrevs for Π
+;; (→ τ_in τ_out) == (Π (unused : τ_in) τ_out)
+(define-simple-macro (→ τ_in ... τ_out)
+  #:with (X ...) (generate-temporaries #'(τ_in ...))
+  (Π ([X : τ_in] ...) τ_out))
+;; (∀ (X) τ) == (∀ ([X : Type]) τ)
+(define-simple-macro (∀ (X ...)  τ)
+  (Π ([X : Type] ...) τ))
+
+;; pattern expanders
+(begin-for-syntax
+  (define-syntax ~Π
+    (pattern-expander
+     (syntax-parser
+       [(_ ([x:id : τ_in] ... (~and (~literal ...) ooo)) τ_out)
+        #'(~∀ (x ... ooo) (~→ τ_in ... ooo τ_out))]
+       [(_ ([x:id : τ_in] ...)  τ_out)
+        #'(~∀ (x ...) (~→ τ_in ... τ_out))]))))
+
+;; equality -------------------------------------------------------------------
+(define-internal-type-constructor =)
+(define-typed-syntax (= t1 t2) ≫
+  [⊢ t1 ≫ t1- ⇒ ty]
+  [⊢ t2 ≫ t2- ⇐ ty]
+  ;; #:do [(printf "t1: ~a\n" (stx->datum #'t1-))
+  ;;       (printf "t2: ~a\n" (stx->datum #'t2-))]
+;  [t1- τ= t2-]
+  ---------------------
+  [⊢ (=- t1- t2-) ⇒ Type])
+
+;; Q: what is the operational meaning of eq-refl?
+(define-typed-syntax (eq-refl e) ≫
+  [⊢ e ≫ e- ⇒ _]
+  ----------
+  [⊢ (#%app- void-) ⇒ (= e- e-)])
+
+;; eq-elim: t : T
+;;          P : (T -> Type)
+;;          pt : (P t)
+;;          w : T
+;;          peq : (= t w)
+;;       -> (P w)
+(define-typed-syntax (eq-elim t P pt w peq) ≫
+  [⊢ t ≫ t- ⇒ ty]
+  [⊢ P ≫ P- ⇐ (→ ty Type)]
+  [⊢ pt ≫ pt- ⇐ (app P- t-)]
+  [⊢ w ≫ w- ⇐ ty]
+  [⊢ peq ≫ peq- ⇐ (= t- w-)]
+  --------------
+  [⊢ pt- ⇒ (app P- w-)])
+
+;; lambda and #%app -----------------------------------------------------------
+
+;; TODO: fix `type` stx class
+(define-typed-syntax λ
+  ;; expected ty only
+  [(_ (y:id ...) e) ⇐ (~Π ([x:id : τ_in] ... ) τ_out) ≫
+   [[x ≫ x- : τ_in] ... ⊢ #,(substs #'(x ...) #'(y ...) #'e) ≫ e- ⇐ τ_out]
+   ---------
+   [⊢ (λ- (x- ...) e-)]]
+  ;; both expected ty and annotations
+  [(_ ([y:id : τ_in*] ...) e) ⇐ (~Π ([x:id : τ_in] ...) τ_out) ≫
+;  [(_ ([y:id : τy_in:type] ...) e) ⇐ (~Π ([x:id : τ_in] ...) τ_out) ≫
+   #:fail-unless (stx-length=? #'(y ...) #'(x ...))
+                 "function's arity does not match expected type"
+   [⊢ τ_in* ≫ τ_in** ⇐ Type] ...
+;   #:when (typechecks? (stx-map (current-type-eval) #'(τ_in* ...))
+   #:when (typechecks? #'(τ_in** ...) #'(τ_in ...))
+;   #:when (typechecks? #'(τy_in.norm ...) #'(τ_in ...))
+;   [τy_in τ= τ_in] ...
+   [[x ≫ x- : τ_in] ... ⊢ #,(substs #'(x ...) #'(y ...) #'e) ≫ e- ⇐ τ_out]
+   -------
+   [⊢ (λ- (x- ...) e-)]]
+  ;; annotations only
+  [(_ ([x:id : τ_in] ...) e) ≫
+   [[x ≫ x- : τ_in] ... ⊢ [e ≫ e- ⇒ τ_out] [τ_in ≫ τ_in- ⇒ _] ...]
+   -------
+   [⊢ (λ- (x- ...) e-) ⇒ (Π ([x- : τ_in-] ...) τ_out)]])
+
+;; helps debug which terms (app/evals) do not have types, eg
+;; - → in internal type representation
+;; - intermediate elim terms
+(define-for-syntax false-tys 0)
+
+;; TODO: fix orig after subst, for err msgs
+;; app/eval should not try to ty check anymore
+(define-syntax app/eval
+  (syntax-parser
+    #;[(_ f . args) #:do[(printf "app/evaling ")
+                       (printf "f: ~a\n" (stx->datum #'f))
+                       (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 ty (typeof this-syntax)
+     ;; TODO: use pat expander instead
+     #: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?
+     #;[
+          (unless (syntax-e #'ty)
+            (displayln 3)
+            (displayln #'ty)
+            (set! false-tys (add1 false-tys))
+            (displayln false-tys))]
+     (maybe-assign-type #'(matcher . args) (typeof this-syntax))]
+    ;; TODO: apply to only lambda args or all args?
+    [(_ (~and f ((~literal #%plain-lambda) (x ...) e)) e_arg ...)
+     #:do[(when debug?
+            (printf "apping: ~a\n" (stx->datum #'f))
+            (printf "args\n")
+            (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
+;     #:with ((~literal #%plain-app) newf . newargs) #'e
+ ;    #:do[(displayln #'newf)(displayln #'newargs)(displayln (stx-car #'e+))]
+     #:with r-app (datum->syntax (if (identifier? #'e) #'e (stx-car #'e)) '#%app)
+     ;; 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
+                    (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 (typeof #'e+)))
+            ;; (displayln "res expanded:------------------------")
+            ;; (pretty-print
+            ;;  (stx->datum (local-expand (substs #'(e_arg ...) #'(x ...) #'e) 'expression null)))
+            (displayln "res app/eval re-expanding-----------------------"))]
+     #:with ((~literal let-values) () ((~literal let-values) () e++))
+            (local-expand
+             #'(let-syntax (#;[app (make-rename-transformer #'app/eval)]
+                            #;[x (make-variable-like-transformer #'e_arg)]) e+)
+                 'expression null)
+     #:do[(when debug?
+            (pretty-print (stx->datum #'e++))
+;            (pretty-print (stx->datum (typeof #'e++)))
+            #;(local-expand
+             #'(let-syntax ([app (make-rename-transformer #'app/eval)]
+                            #;[x (make-variable-like-transformer #'e_arg)]) e+)
+             'expression null))]
+     #;[(when (not (syntax-e #'ty))
+            (displayln 1)
+            (displayln (stx->datum this-syntax))
+            (displayln #'ty)
+            (set! false-tys (add1 false-tys))
+            (displayln false-tys))]
+     #'e++ #;(substs #'(e_arg ...) #'(x ...) #'e)]
+    [(_ f . args)
+    #:do[(when debug?
+           (printf "not apping\n")
+           (pretty-print (stx->datum #'f))
+           (displayln "args")
+           (pretty-print (stx->datum #'args)))]
+     #:with f+ (expand/df #'f)
+     #:with args+ (stx-map expand/df #'args)
+     ;; TODO: need to attach type?
+     #:with ty (typeof this-syntax)
+     #;[(unless (syntax-e #'ty)
+            (displayln 2)
+            (displayln (stx->datum this-syntax))
+            (displayln #'ty)
+            (displayln (syntax-property this-syntax '::))
+            (set! false-tys (add1 false-tys))
+            (displayln false-tys))]
+     (syntax-parse #'f+
+       [((~literal #%plain-lambda) . _)
+        (maybe-assign-type #'(app/eval f+ . args+) #'ty)]
+       [_
+        ;(maybe-assign-type
+         #'(#%app- f+ . args+)
+         ;#'ty)
+        ])]))
+     
+;; TODO: fix orig after subst
+(define-typed-syntax app
+  [(_ e_fn e_arg ...) ≫
+   #:do[(when debug?
+          (displayln "TYPECHECKING")
+          (pretty-print (stx->datum this-syntax)))]
+;   #:do[(printf "applying (1) ~a\n" (stx->datum #'e_fn))]
+;   [⊢ e_fn ≫ (~and e_fn- (_ (x:id ...) e ~!)) ⇒ (~Π ([X : τ_inX] ...) τ_outX)]
+   [⊢ e_fn ≫ e_fn- ⇒ (~Π ([X : τ_in] ...) τ_out)]
+   #:fail-unless (stx-length=? #'[τ_in ...] #'[e_arg ...])
+                 (num-args-fail-msg #'e_fn #'[τ_in ...] #'[e_arg ...])
+   ;; #:do[(displayln "expecting")
+   ;;      (pretty-print (stx->datum #'(τ_in ...)))]
+   ;; [⊢ e_arg ≫ _ ⇒ ty2] ... ; typechecking args
+   ;; #:do[(displayln "got")
+   ;;      (pretty-print (stx->datum (stx-map typeof #'(ty2 ...))))]
+   [⊢ e_arg ≫ e_arg- ⇐ τ_in] ... ; typechecking args
+   -----------------------------
+   [⊢ (app/eval e_fn- e_arg- ...) ⇒ #,(substs #'(e_arg- ...) #'(X ...) #'τ_out)]])
+   
+(define-typed-syntax (ann e (~datum :) τ) ≫
+  [⊢ e ≫ e- ⇐ τ]
+  --------
+  [⊢ e- ⇒ τ])
+
+;; top-level ------------------------------------------------------------------
+;; TODO: shouldnt need define-type-alias, should be same as define
+(define-syntax define-type-alias
+  (syntax-parser
+    [(_ alias:id τ);τ:any-type)
+     #'(define-syntax- alias
+         (make-variable-like-transformer #'τ))]
+    #;[(_ (f:id x:id ...) ty)
+     #'(define-syntax- (f stx)
+         (syntax-parse stx
+           [(_ x ...)
+            #:with τ:any-type #'ty
+            #'τ.norm]))]))
+
+;; TODO: delete this?
+(define-typed-syntax define
+  [(_ x:id (~datum :) τ e:expr) ≫
+   [⊢ e ≫ e- ⇐ τ]
+   #:with y (generate-temporary #'x)
+   #:with y+props (transfer-props #'e- #'y #:except '(origin))
+   --------
+   [≻ (begin-
+        (define-syntax x (make-rename-transformer #'y+props))
+        (define- y e-))]]
+  [(_ x:id e) ≫
+   ;This won't work with mutually recursive definitions
+   [⊢ e ≫ e- ⇒ _]
+   #:with y (generate-temporary #'x)
+   #:with y+props (transfer-props #'e- #'y #:except '(origin))
+   --------
+   [≻ (begin-
+        (define-syntax x (make-rename-transformer #'y+props))
+        (define- y e-))]]
+  #;[(_ (f [x (~datum :) ty] ... (~or (~datum →) (~datum ->)) ty_out) e ...+) ≫
+   #:with f- (add-orig (generate-temporary #'f) #'f)
+   --------
+   [≻ (begin-
+        (define-syntax- f
+          (make-rename-transformer (⊢ f- : (→ ty ... ty_out))))
+        (define- f-
+          (stlc+lit:λ ([x : ty] ...)
+            (stlc+lit:ann (begin e ...) : ty_out))))]])
+
+
+(define-typed-syntax (unsafe-assign-type e (~datum :) τ) ≫ --- [⊢ e ⇒ τ])
+
+(struct TmpTy- ())
+(define-syntax TmpTy
+  (syntax-parser
+    [:id (assign-type #'TmpTy- #'Type)]
+    [(_ . args) (assign-type #'(#%app TmpTy- . args) #'Type)]))
+
+(struct match/delayed (name args) #:transparent)
+
+(define-typed-syntax define-datatype
+  ;; datatype type `TY` is an id ----------------------------------------------
+  ;; - ie, no params or indices
+  [(_ Name (~datum :) TY: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)
+   ;; un-subst TmpTy for Name in expanded CTY
+   ;; TODO: replace TmpTy in origs of CTY_in ... CTY_out
+   ;; TODO: check CTY_out == `Name`?
+   #:with ((~Π ([x : CTY_in] ...) CTY_out) ...)
+          (subst #'Name #'TmpTy+ #'(CTY/tmp- ...) free-id=?)
+   #:with (C/internal ...) (generate-temporaries #'(C ...))
+   #:with (Ccase ...) (generate-temporaries #'(C ...))
+   #: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) ; returns x or #f
+                                     (and (free-id=? t #'Name) x))
+                                   xs ts)))
+                               #'((x ...) ...) #'((CTY_in ...) ...))
+   #:with elim-Name (format-id #'Name "elim-~a" #'Name)
+   #:with match-Name (format-id #'Name "match-~a" #'Name)
+   #:with Name/internal (generate-temporary #'Name)
+   --------
+   [≻ (begin-
+        ;; define `Name`, eg "Nat", as a valid type
+;        (define-base-type Name) ; dont use bc uses '::, and runtime errs
+        (struct Name/internal ())
+        (define-typed-syntax Name [_:id ≫ --- [⊢ (Name/internal) ⇒ TY]])
+        ;; define structs for `C` constructors
+        (struct C/internal (x ...) #:transparent) ...
+        (define C (unsafe-assign-type C/internal : CTY)) ...
+        ;; elimination form
+        (define-typed-syntax (elim-Name v P Ccase ...) ≫
+          [⊢ v ≫ v- ⇐ Name]
+          [⊢ P ≫ P- ⇐ (→ Name Type)] ; prop / motive
+          ;; each `Ccase` require 2 sets of args (even if set is empty):
+          ;; 1) args of the constructor `x` ... 
+          ;; 2) IHs for each `x` that has type `Name`
+          [⊢ Ccase ≫ Ccase- ⇐ (Π ([x : CTY_in] ...)
+                                 (→ (app P- recur-x) ...
+                                    (app P- (app C x ...))))] ...
+          -----------
+          [⊢ (match-Name v- P- Ccase- ...) ⇒ (app P- v-)])
+        ;; eval the elim redexes
+        (define-syntax match-Name
+          (syntax-parser
+            #;[(_ . args)
+             #:do[(printf "trying to match:\n~a\n" (stx->datum #'args))]
+             #:when #f #'(void)]
+            [(_ v P Ccase ...)
+             #:with ty (typeof this-syntax)
+             ; local expand since v might be unexpanded due to reflection
+             (syntax-parse (local-expand #'v 'expression null)
+               ; do eval if v is an actual `C` instance
+               [((~literal #%plain-app) C-:id x ...)
+                #:with (_ C+ . _) (local-expand #'(C 'x ...) 'expression null)
+                #:when (free-identifier=? #'C- #'C+)
+                (maybe-assign-type
+                 #`(app/eval (app Ccase x ...)
+;                             (match-Name x P Ccase ...) ...)
+                             #,@(stx-map (lambda (y)
+                                           (maybe-assign-type
+                                            #`(match-Name #,y P Ccase ...)
+                                           #'ty))
+                                         #'(x ...)))
+                 #'ty)]
+               ...
+               ; else generate a delayed term
+               ;; must be #%app-, not #%plain-app, ow match will not dispatch properly
+               [_ ;(maybe-assign-type
+                   #'(#%app- match/delayed 'match-Name (void v P Ccase ...))
+                   ;#'ty)
+                  ])]))
+        )]]
+  ;; --------------------------------------------------------------------------
+  ;; datatype type `TY` is a fn:
+  ;; - params A ... and indices i ... must be in separate fn types
+  ;; - but actual type formation constructor flattens to A ... i ...
+  ;; - and constructors also flatten to A ... i ...
+  ;; - all cases in elim-Name must consume i ... (but A ... is inferred)
+  ;; --------------------------------------------------------------------------
+  [(_ Name (~datum :) TY
+      [C:id (~datum :) CTY] ...) ≫
+
+   ;; params and indices specified with separate fn types, to distinguish them,
+   ;; but are combined in other places,
+   ;; eg (Name A ... i ...) or (CTY A ... i ...)
+   [⊢ TY ≫ (~Π ([A : TYA] ...) ; params
+               (~Π ([i : TYi] ...) ; indices
+                   TY_out)) ⇐ Type]
+
+   ; need to expand `CTY` but `Name` is still unbound so use tmp id
+   ; - extract arity of each `C` ...
+   ; - find recur args   
+   #:with (CTY/tmp ...) (subst #'TmpTy #'Name #'(CTY ...))
+   [⊢ CTY/tmp ≫ CTY/tmp- ⇐ Type] ...
+   #:with (_ TmpTy+) (local-expand #'(TmpTy) 'expression null)
+   ;; ;; TODO: replace TmpTy in origs of τ_in ... τ_out
+   ;; 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 `elim` macro below
+   ;;
+   ;; - 1st Π is tycon params, dont care for now
+   ;; - 2nd Π is tycon indices, dont care for now
+   ;; - 3rd Π is constructor args
+   #:with ((~Π ([_ : _] ...)
+             (~Π ([_ : _] ...)
+               (~Π ([x : CTY_in/tmp] ...) CTY_out/tmp))) ...)
+          #'(CTY/tmp- ...)
+   ;; each (recur-x ...) is subset of (x ...) that are recur args,
+   ;; ie, they are not fresh ids
+   #:with ((recur-x ...) ...) (stx-map
+                               (lambda (xs ts)
+                                 (filter
+                                  (lambda (y) y) ; filter out #f
+                                  (stx-map
+                                   (lambda (x t)
+                                     (and
+                                      (syntax-parse t
+                                        [((~literal #%plain-app) tmp . _)
+                                         (free-id=? #'tmp #'TmpTy+)]
+                                        [_ #f])
+                                      x)) ; returns x or #f
+                                   xs ts)))
+                               #'((x ...) ...)
+                               #'((CTY_in/tmp ...) ...))
+   #:with ((recur-Cx ...) ...) (stx-map generate-temporaries #'((recur-x ...) ...))
+
+   ;; pre-generate other patvars; makes nested macros below easier to read
+   #:with (A- ...) (generate-temporaries #'(A ...))
+   #:with (i- ...) (generate-temporaries #'(i ...))
+   ;; need to multiply A and i patvars, to match types of `C` ... constructors
+   ;; must be fresh vars to avoid dup patvar errors
+   #:with ((CA ...) ...) (stx-map (lambda _ (generate-temporaries #'(A ...))) #'(C ...))
+   #:with ((CTYA ...) ...) (stx-map (lambda _ (generate-temporaries #'(A ...))) #'(C ...))
+   #:with ((Ci ...) ...) (stx-map (lambda _ (generate-temporaries #'(i ...))) #'(C ...))
+   #:with ((CTYi/CA ...) ...) (stx-map (lambda _ (generate-temporaries #'(TYi ...))) #'(C ...))
+   #:with ((CTYi ...) ...) (stx-map (lambda _ (generate-temporaries #'(TYi ...))) #'(C ...))
+   #:with ((Cx ...) ...) (stx-map (lambda (xs) (generate-temporaries xs)) #'((x ...) ...))
+   ; Ci*recur dups Ci for each recur, to get the ellipses to work out below
+   #:with (((Ci*recur ...) ...) ...) (stx-map
+                                      (lambda (cis recurs)
+                                        (stx-map (lambda (r) cis) recurs))
+                                      #'((Ci ...) ...)
+                                      #'((recur-x ...) ...))
+   ;; not inst'ed CTY_in
+   #:with ((CTY_in/CA ...) ...) (stx-map generate-temporaries #'((CTY_in/tmp ...) ...))
+   ;; inst'ed CTY_in (with A ...)
+   #:with ((CTY_in ...) ...) (stx-map generate-temporaries #'((CTY_in/tmp ...) ...))
+   #:with (CTY_out/CA ...) (generate-temporaries #'(C ...))
+   #:with (CTY_out ...) (generate-temporaries #'(C ...))
+   ; CTY_out_A matches the A and CTY_out_i matches the i in CTY_out,
+   ; - ie CTY_out = (Name CTY_out_A ... CTY_out_i ...)
+   ; - also, CTY_out_A refs (ie bound-id=) CA and CTY_out_i refs Ci
+   #:with ((CTY_out_A ...) ...) (stx-map (lambda _ (generate-temporaries #'(A ...))) #'(C ...))
+   #:with ((CTY_out_i ...) ...) (stx-map (lambda _ (generate-temporaries #'(i ...))) #'(C ...))
+   ;; differently named `i`, to match type of P
+   #:with (j ...) (generate-temporaries #'(i ...))
+   ; dup (A ...) C times, again for ellipses matching
+   #:with ((A*C ...) ...) (stx-map (lambda _ #'(A ...)) #'(C ...))
+   #:with (C/internal ...) (generate-temporaries #'(C ...))
+   #:with (Ccase ...) (generate-temporaries #'(C ...))
+   #:with (Ccase- ...) (generate-temporaries #'(C ...))
+   #:with Name- (mk-- #'Name)
+   #:with Name-patexpand (mk-~ #'Name)
+   #:with elim-Name (format-id #'Name "elim-~a" #'Name)
+   #:with match-Name (format-id #'Name "match-~a" #'Name)
+   #:with (ccasety ...) (generate-temporaries #'(Ccase ...))
+   ;; these are all the generated definitions that implement the define-datatype
+   #:with OUTPUT-DEFS
+    #'(begin-
+        ;; define the type
+        (define-internal-type-constructor Name)
+        ;; TODO? This works when TYi depends on (e.g., is) A
+        ;; but is this always the case?
+        (define-typed-syntax (Name A ... i ...) ≫
+          [⊢ A ≫ A- ⇐ TYA] ...
+          [⊢ i ≫ i- ⇐ TYi] ...
+          ----------
+          [⊢ (Name- A- ... i- ...) ⇒ TY_out])
+
+        ;; define structs for constructors
+        (struct C/internal (x ...) #:transparent) ...
+        ;; TODO: this define should be a macro instead?
+        (define C (unsafe-assign-type
+                   (lambda (A ...) (lambda (i ...) C/internal))
+                   : CTY)) ...
+
+        ;; define eliminator-form
+        (define-typed-syntax (elim-Name v P Ccase ...) ≫
+          ;; re-extract CTY_in and CTY_out, since we didnt un-subst above
+          ;; TODO: must re-compute recur-x, ie recur-Cx
+          #:with ((~Π ([CA : CTYA] ...) ; ignore params, instead infer `A` ... from `v`
+                    (~Π ([Ci : CTYi/CA] ...)
+                      (~Π ([Cx : CTY_in/CA] ...)
+                          CTY_out/CA)))
+                  ...)
+                 (stx-map (current-type-eval) #'(CTY ...))
+
+          ;; compute recur-Cx by finding analogous x/recur-x pairs
+          ;; each (recur-Cx ...) is subset of (Cx ...) that are recur args,
+          ;; ie, they are not fresh ids
+          #:with ((recur-Cx ...) ...)
+                 (stx-map
+                  (lambda (xs rxs cxs)
+                    (filter
+                     (lambda (z) z) ; filter out #f
+                     (stx-map
+                      (lambda (y cy)
+                        (if (stx-member y rxs) cy #f))
+                      xs cxs)))
+                  #'((x ...) ...)
+                  #'((recur-x ...) ...)
+                  #'((Cx ...) ...))
+          #;(stx-map
+                                      (lambda (xs ts)
+                                        (filter
+                                         (lambda (y) y) ; filter out #f
+                                         (stx-map
+                                          (lambda (x t)
+                                            (and
+                                             (syntax-parse t
+                                               [(Name-patexpand . _) #t]
+                                               [_ #f])
+                                             x)) ; returns x or #f
+                                          xs ts)))
+                                      #'((Cx ...) ...)
+                                      #'((CTY_in/CA ...) ...))
+
+          ;; target, infers A ...
+          [⊢ v ≫ v- ⇒ (Name-patexpand A ... i ...)]
+
+          ;; inst CTY_in/CA and CTY_out/CA with inferred A ...
+          #:with (((CTYi ...)
+                   (CTY_in ... CTY_out))
+                  ...)
+                 (stx-map (lambda (ts tyis cas) (substs #'(A ...) cas #`(#,tyis #,ts)))
+                          #'((CTY_in/CA ... CTY_out/CA) ...)
+                          #'((CTYi/CA ...) ...)
+                          #'((CA ...) ...))
+          ;; get the params and indices in CTY_out
+          ;; - dont actually need CTY_out_A
+          #:with ((Name-patexpand CTY_out_A ... CTY_out_i ...) ...) #'(CTY_out ...)
+
+          ;; prop / motive
+          [⊢ P ≫ P- ⇐ (Π ([j : TYi] ...) (→ (Name A ... j ...) Type))]
+
+          ;; each Ccase consumes 3 nested sets of (possibly empty) args:
+          ;; 1) Ci  - indices of the tycon
+          ;; 2) Cx   - args of each constructor `C`
+          ;; 3) IHs - for each recur-Cx ... (which are a subset of Cx ...)
+          ;;
+          ;; somewhat of a hack:
+          ;; by reusing Ci and CTY_out_i both to match CTY/CTY_out above, and here,
+          ;; we automatically unify Ci with the indices in CTY_out
+          [⊢ Ccase ≫ _ ⇒ ccasety] ...
+          [⊢ Ccase ≫ Ccase- ⇐ (Π ([Ci : CTYi] ...) ; indices
+                                 (Π ([Cx : CTY_in] ...) ; constructor args
+                                    (→ (app (app P- Ci*recur ...) recur-Cx) ... ; IHs
+                                       (app (app P- CTY_out_i ...)
+                                            (app (app (app C A*C ...) Ci ...) Cx ...)))))] ...
+          -----------
+          [⊢ (match-Name v- P- Ccase- ...) ⇒ (app (app P- i ...) v-)])
+
+        ;; implements reduction of elimator redexes
+        (define-syntax match-Name
+          (syntax-parser
+            #;[(_ . args)
+             #:do[(displayln "trying to match:")
+                  (pretty-print (stx->datum #'args))]
+             #:when #f #'(void)]
+            [(_ v P Ccase ...)
+             #:with ty (typeof this-syntax)
+             ;; must local expand because `v` may be unexpanded due to reflection
+             (syntax-parse (local-expand #'v 'expression null)
+               [((~literal #%plain-app)
+                 ((~literal #%plain-app)
+                  ((~literal #%plain-app) C-:id CA ...)
+                  Ci ...)
+                 x ...)
+                #:with (_ C+ . _) (local-expand #'(C 'CA ...) 'expression null)
+                #:when (free-identifier=? #'C+ #'C-)
+                ;; can use app instead of app/eval to properly propagate types
+                ;; but doesnt quite for in all cases?
+                (maybe-assign-type
+                 #`(app/eval ;#,(assign-type
+                                (app/eval (app Ccase Ci ...) x ...)
+                                ;; TODO: is this right?
+                              ;       #'(app P Ci ...))
+;                             (match-Name recur-x P Ccase ...) ...)
+                             #,@(stx-map (lambda (r)
+                                           (maybe-assign-type
+                                            #`(match-Name #,r P Ccase ...)
+                                            #'ty))
+                                         #'(recur-x ...)))
+                 #'ty)] ...
+               [_ ;(maybe-assign-type
+                   ;; must be #%app-, not #%plain-app, ow match will not dispatch properly
+                   #'(#%app- match/delayed 'match-Name (void v P Ccase ...))
+                   ;#'ty)
+                  ])])))
+   ;; DEBUG: of generated defs
+;   #:do[(pretty-print (stx->datum #'OUTPUT-DEFS))]
+   --------
+   [≻ OUTPUT-DEFS]])
diff --git a/turnstile/examples/dep-ind.rkt b/turnstile/examples/dep-ind.rkt
index 124cf9b..b08d8f5 100644
--- a/turnstile/examples/dep-ind.rkt
+++ b/turnstile/examples/dep-ind.rkt
@@ -393,7 +393,7 @@
 (struct match/delayed (name args) #:transparent)
 
 (define-typed-syntax define-datatype
-  ;; datatype type `TY` is an id ---------------------------------------------------
+  ;; datatype type `TY` is an id ----------------------------------------------
   ;; - ie, no params or indices
   [(_ Name (~datum :) TY:id
       [C:id (~datum :) CTY] ...) ≫
diff --git a/turnstile/examples/tests/dep-ind-eq-tests.rkt b/turnstile/examples/tests/dep-ind-eq-tests.rkt
new file mode 100644
index 0000000..ef8e680
--- /dev/null
+++ b/turnstile/examples/tests/dep-ind-eq-tests.rkt
@@ -0,0 +1,84 @@
+#lang s-exp "../dep-ind-fixed.rkt"
+(require "rackunit-typechecking.rkt")
+
+; Π → λ ∀ ≻ ⊢ ≫ ⇒
+
+;; testing user-defined equality
+
+(define-datatype my= : (Π ([A : (Type 0)]) (Π ([a : A] [b : A]) (Type 0)))
+  (my-refl : (Π ([A : (Type 0)])
+                (Π ([x : A][y : A])
+                   (Π ([a : A]) (my= A a a))))))
+
+(define-datatype Nat : *
+  [Z : (→ Nat)]
+  [S : (→ Nat Nat)])
+
+(define-type-alias plus
+  (λ ([n : Nat][m : Nat])
+    (elim-Nat n
+              (λ ([k : Nat]) Nat)
+              (λ () (λ () m))
+              (λ ([k : Nat]) (λ ([IH : Nat]) (S IH))))))
+
+;; index args (the Z's) to my-refl are unused
+;; TODO: drop them?
+(check-type (((my-refl Nat) (Z) (Z)) (Z)) : (my= Nat (Z) (Z))) ; 0=0
+(check-not-type (((my-refl Nat) (Z) (Z)) (S (Z))) : (my= Nat (Z) (Z))) ; 1 \neq 0
+(check-type (((my-refl Nat) (Z) (Z)) (S (Z)))
+            : (my= Nat (S (Z)) (S (Z)))) ; 1=1
+(check-type (((my-refl Nat) (Z) (Z)) (S (Z)))
+            : (my= Nat (S (Z)) (plus (S (Z)) (Z)))) ; 1=1+0
+(check-type (((my-refl Nat) (Z) (Z)) (S (Z)))
+            : (my= Nat (plus (S (Z)) (Z)) (plus (S (Z)) (Z)))) ; 1+0=1+0
+(check-type (((my-refl Nat) (Z) (Z)) (S (Z)))
+            : (my= Nat (plus (Z) (S (Z))) (plus (S (Z)) (Z)))) ; 1+0=0+1
+(check-type
+ (((my-refl Nat) (Z) (Z)) (S (S (Z))))
+ : (my= Nat (plus (S (Z)) (S (Z))) (plus (S (Z)) (plus (S (Z)) (Z))))) ; 1+1=1+1+0
+
+;; = symmetric
+(check-type
+ (λ ([B : (Type 0)])
+   (λ ([x : B] [y : B])
+       (λ ([e : (my= B x y)])
+         (elim-my=
+          e
+          (λ ([a : B] [b : B])
+             (λ ([e : (my= B a b)])
+               (my= B b a)))
+          (λ ([a : B] [b : B])
+            (λ ([c : B])
+              (λ ()
+                (((my-refl B) c c) c))))))))
+ : (Π ([A : (Type 0)])
+      (Π ([x : A] [y : A])
+         (→ (my= A x y) (my= A y x)))))
+
+;; = transitive
+; TODO
+#;(check-type
+ (λ ([A : (Type 0)])
+   (λ ([x : A] [y : A] [z : A])
+      (λ ([e1 : (my= A x y)] [e2 : (my= A y z)])
+         (elim-my=
+          e1
+          (λ ([a : A] [b : A])
+             (λ ([e : (my= A a b)])
+               (my= A a z)))
+          (λ ([a : A] [b : A])
+            (λ ([c : A])
+              (λ ()
+                (elim-my=
+                 e2
+                 (λ ([a : A] [b : A])
+                    (λ ([e : (my= A a b)])
+                      (my= A c c)))
+                 (λ ([a : A] [b : A])
+                   (λ ([c : A])
+                     (λ ()
+                       (((my-refl A) c c) c))))))))))))
+ : (Π ([A : (Type 0)])
+      (Π ([x : A] [y : A] [z : A])
+         (→ (my= A x y) (my= A y z) (my= A x z)))))
+   
diff --git a/turnstile/examples/tests/dep-ind-fixed-list-tests.rkt b/turnstile/examples/tests/dep-ind-fixed-list-tests.rkt
new file mode 100644
index 0000000..698455f
--- /dev/null
+++ b/turnstile/examples/tests/dep-ind-fixed-list-tests.rkt
@@ -0,0 +1,271 @@
+#lang s-exp "../dep-ind-fixed.rkt"
+(require "rackunit-typechecking.rkt")
+
+; Π → λ ∀ ≻ ⊢ ≫ ⇒
+
+;; same as dep-ind-list-tests except uses dep-ind-fixed
+;; - constructor params and indices must be applied separately
+
+(define-datatype Nat : *
+  [Z : (→ Nat)]
+  [S : (→ Nat Nat)])
+
+;; some basic tests
+(check-type Nat : *)
+;; this test wont work if define-datatype uses define-base-type
+(check-type (λ ([x : Nat]) Nat) : (→ Nat *))
+
+;; constructors require 3 sets of args:
+;; 1) params
+;; 2) indices
+;; 3) constructor args, split into
+;;    - non-recursive
+;;    - recursive
+(define-datatype List : (→ * (→ *))
+  [null : (∀ (A) (→ (→ (List A))))]
+  [cons : (∀ (A) (→ (→ A (List A) (List A))))])
+
+(check-type null : (∀ (A) (→ (→ (List A)))))
+(check-type cons : (∀ (A) (→ (→ A (List A) (List A)))))
+(check-type (null Nat) : (→ (→ (List Nat))))
+(check-type (cons Nat) : (→ (→ Nat (List Nat) (List Nat))))
+(check-type ((null Nat)) : (→ (List Nat)))
+(check-type (((null Nat))) : (List Nat))
+(check-type (((cons Nat)) (Z) (((null Nat)))) : (List Nat))
+
+;; length 0
+(check-type
+ (elim-List (((null Nat)))
+            (λ () (λ ([l : (List Nat)]) Nat))
+            (λ () (λ () (λ () (Z))))
+            (λ ()
+              (λ ([x : Nat][xs : (List Nat)])
+                (λ ([IH : Nat])
+                  (S IH)))))
+ : Nat
+ -> (Z))
+
+;; length 1
+(check-type
+ (elim-List (((cons Nat)) (Z) (((null Nat))))
+            (λ () (λ ([l : (List Nat)]) Nat))
+            (λ () (λ () (λ () (Z))))
+            (λ ()
+              (λ ([x : Nat][xs : (List Nat)])
+                (λ ([IH : Nat])
+                  (S IH)))))
+ : Nat
+ -> (S (Z)))
+
+;; length 2
+(check-type
+ (elim-List (((cons Nat)) (S (Z)) (((cons Nat)) (Z) (((null Nat)))))
+            (λ () (λ ([l : (List Nat)]) Nat))
+            (λ () (λ () (λ () (Z))))
+            (λ () 
+              (λ ([x : Nat][xs : (List Nat)])
+                (λ ([IH : Nat])
+                  (S IH)))))
+ : Nat
+ -> (S (S (Z))))
+
+(define-type-alias len/Nat
+  (λ ([lst : (List Nat)])
+    (elim-List lst
+               (λ () (λ ([l : (List Nat)]) Nat))
+               (λ () (λ () (λ () (Z))))
+               (λ ()
+                 (λ ([x : Nat][xs : (List Nat)])
+                   (λ ([IH : Nat])
+                     (S IH)))))))
+
+(check-type (len/Nat (((null Nat)))) : Nat -> (Z))
+(check-type (len/Nat (((cons Nat)) (Z) (((null Nat))))) : Nat -> (S (Z)))
+
+(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)))))])
+
+(check-type nil : (Π ([A : *]) (Π ([k : Nat]) (→ (Vect A (Z))))))
+(check-type cns : (Π ([A : *]) (Π ([k : Nat]) (→ A (Vect A k) (Vect A (S k))))))
+
+(check-type ((nil Nat) (Z)) : (→ (Vect Nat (Z))))
+(check-type ((cns Nat) (Z)) : (→ Nat (Vect Nat (Z)) (Vect Nat (S (Z)))))
+
+(check-type (((nil Nat) (Z))) : (Vect Nat (Z)))
+(check-type (((cns Nat) (Z)) (Z) (((nil Nat) (Z)))) : (Vect Nat (S (Z))))
+(check-type (((cns Nat) (S (Z))) (Z)
+             (((cns Nat) (Z)) (Z)
+              (((nil Nat) (Z)))))
+            : (Vect Nat (S (S (Z)))))
+
+(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)))
+            (λ ([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))))
+            (λ ([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)))))
+            (λ ([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)))))))
diff --git a/turnstile/examples/tests/dep-ind-fixed-tests.rkt b/turnstile/examples/tests/dep-ind-fixed-tests.rkt
new file mode 100644
index 0000000..c989c5b
--- /dev/null
+++ b/turnstile/examples/tests/dep-ind-fixed-tests.rkt
@@ -0,0 +1,153 @@
+#lang s-exp "../dep-ind-fixed.rkt"
+(require "rackunit-typechecking.rkt")
+
+; Π → λ ∀ ≻ ⊢ ≫ ⇒
+
+; should be identical to dep-ind-tests.rkt
+; since dep-ind-fixed does not change
+; first clause of define-datatype
+
+;; examples from Prabhakar's Proust paper
+
+;; this file is like dep-peano-tests.rkt except it uses
+;; define-datatype from #lang dep-ind.rkt to define Nat,
+;; instead of using the builtin Nat from #lang dep.rkt
+
+;; the examples in this file are mostly identical to dep-peano-tests.rkt,
+;; except Z is replaced with (Z)
+
+;; check (Type n) : (Type n+1)
+(check-type Type : (Type 1))
+(check-type (Type 0) : (Type 1))
+(check-not-type (Type 0) : (Type 0))
+(check-type (Type 1) : (Type 2))
+(check-type (Type 3) : (Type 4))
+
+(typecheck-fail ((λ ([x : Type]) x) Type)
+ #:with-msg "expected Type, given \\(Type 1\\)")
+(check-type ((λ ([x : (Type 1)]) x) Type) : (Type 1))
+(check-type ((λ ([x : (Type 2)]) x) (Type 1)) : (Type 2))
+
+;; Peano nums -----------------------------------------------------------------
+
+(define-datatype Nat : *
+  [Z : (→ Nat)]
+  [S : (→ Nat Nat)])
+
+; TODO: special case 0-arity constructor using id macro
+(check-type Z : (→ Nat))
+(check-type S : (→ Nat Nat))
+;(check-type Z : Nat -> Z)
+(check-type (Z) : Nat -> (Z))
+(check-type (S (Z)) : Nat -> (S (Z)))
+(check-type (S (S (Z))) : Nat -> (S (S (Z))))
+
+(define-type-alias nat-rec
+  (λ ([C : *])
+    (λ ([zc : (→ C)][sc : (→ C C)])
+      (λ ([n : Nat])
+        (elim-Nat n
+                  (λ ([x : Nat]) C)
+                  (λ () zc)
+                  (λ ([x : Nat]) sc))))))
+(check-type nat-rec : (∀ (C) (→ (→ C) (→ C C) (→ Nat C))))
+
+;; nat-rec with no annotations
+(check-type
+  (λ (C)
+    (λ (zc sc)
+      (λ (n)
+        (elim-Nat n
+                  (λ (x) C)
+                  (λ () zc)
+                  (λ (x) sc)))))
+  : (∀ (C) (→ (→ C) (→ C C) (→ Nat C))))
+
+(check-type (nat-rec Nat) : (→ (→ Nat) (→ Nat Nat) (→ Nat Nat)))
+(check-type ((nat-rec Nat) Z (λ ([n : Nat]) (S n))) : (→ Nat Nat))
+
+;; basic identity example, to test eval
+(define-type-alias id ((nat-rec Nat) Z (λ ([n : Nat]) (S n))))
+
+(check-type (id (Z)) : Nat -> (Z))
+;; this example will err if eval tries to tycheck again
+(check-type (id (S (Z))) : Nat)
+(check-type (id (S (Z))) : Nat -> (S (Z)))
+
+(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)))
+
+;; infer, and dont curry
+(check-type
+ (λ (n1 n2)
+   ((((nat-rec (→ Nat Nat))
+      (λ () (λ (m) m))
+      (λ (pm) (λ (x) (S (pm x)))))
+     n1)
+    n2))
+ : (→ 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)
+;(check-type ((plus (S Z)) Z) : Nat -> 1)
+(check-type (plus (Z)) : (→ Nat Nat))
+(check-type ((plus (Z)) (Z)) : Nat -> (Z))
+(check-type ((plus (Z)) (S (Z))) : Nat -> (S (Z)))
+(check-type ((plus (S (Z))) (Z)) : Nat -> (S (Z)))
+(check-type ((plus (S (Z))) (S (Z))) : Nat -> (S (S (Z))))
+(check-type ((plus (S (S (Z)))) (S (Z))) : Nat -> (S (S (S (Z)))))
+(check-type ((plus (S (Z))) (S (S (Z)))) : Nat -> (S (S (S (Z)))))
+
+;; plus zero (left)
+(check-type (λ ([n : Nat]) (eq-refl n))
+            : (Π ([n : Nat]) (= ((plus (Z)) n) n)))
+
+;; plus zero (right)
+(check-type
+ (λ ([n : Nat])
+   (elim-Nat n
+             (λ ([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 : Nat]) (= ((plus n) (Z)) n)))
+
+;; plus zero identity, no annotations
+;; left:
+(check-type (λ (n) (eq-refl n))
+            : (Π ([n : Nat]) (= ((plus (Z)) n) n)))
+;; right:
+(check-type
+ (λ (n)
+   (elim-Nat n
+             (λ (m) (= ((plus m) (Z)) m))
+             (λ () (λ () (eq-refl (Z))))
+             (λ (k) (λ (p)
+               (eq-elim ((plus k) (Z))
+                        (λ (W) (= (S ((plus k) (Z))) (S W)))
+                        (eq-refl (S ((plus k) (Z))))
+                        k
+                        p)))))
+ : (Π ([n : Nat]) (= ((plus n) (Z)) n))
+)
+;; nat-ind as a function ; TODO: need matching form or matching lambda
+#;(define-typed-alias nat-ind2
+  (λ ([P : (→ Nat *)]
+      [Zcase : (P Z)]
+      [Scase : (Π ([k : Nat]) (→ (P k) (P (S k))))]
+      [n : Nat])
+    (match/nat n ZCase (SCase n (nat-ind2 P ZCase SCase n-1)))))