cur/example.rkt
William J. Bowman 89c5c1ba68 Fixed various bugs related to case and inductives
case would fail when used on an inductive family. Fixed this, added more
test cases, and cleaned up examples.
2015-01-16 22:54:35 -05:00

224 lines
6.4 KiB
Racket

#lang s-exp "redex-core.rkt"
;; Use racket libraries over your dependently typed code!?!?
;; TODO: actually, I'm not sure this should work quite as well as it
;; seems to with check-equal?
(require rackunit)
;; -------------------
;; Define inductive data
(data true : Type (T : true))
(data false : Type)
;; -------------------
;; Look, syntax extension!
(define-syntax (-> syn)
(syntax-case syn ()
[(_ t1 t2)
(with-syntax ([(x) (generate-temporaries '(1))])
#'(forall (x : t1) t2))]))
(data nat : Type
(z : nat)
(s : (-> nat nat)))
(define nat-is-now-a-type
(lambda (y : (-> nat nat))
(lambda (x : nat) (y x))))
;; -------------------
;; Lexical scoping! I can reuse the name nat!
(define nat-is-just-a-name (lambda (nat : Type) nat))
;; -------------------
;; Reuse some familiar syntax
(define y (lambda (x : true) x))
(define (y1 (x : true)) x)
(define (y2 (x1 : true) (x2 : true)) x1)
;; -------------------
;; Unit test dependently typed code!
(check-equal? (y2 T T) T)
;; -------------------
;; Write functions on inductive data
(define (add1 (n : nat)) (s n))
(check-equal? (add1 (s z)) (s (s z)))
(define (sub1 (n : nat))
(case n
[z z]
;; TODO: Add macro to enable writing this line as:
;; [(s x) (s (s x))]
[s (lambda (x : nat) x)]))
(check-equal? (sub1 (s z)) z)
#|
;; TODO: Plus require recursion and I don't have recursion!
(define (plus (n1 : nat) (n2 : nat))
(case n1
[z n2]
[s (λ (x : nat) (plus x (s n2)))]))
(check-equal? (plus (s (s z)) (s (s z))) (s (s (s z))))
|#
;; -------------------
;; It's annoying to have to write things explicitly curried
;; Macros to the rescue!
(define-syntax forall*
(syntax-rules (:)
[(_ (a : t) (ar : tr) ... b)
(forall (a : t)
(forall* (ar : tr) ... b))]
[(_ b) b]))
(define-syntax lambda*
(syntax-rules (:)
[(_ (a : t) (ar : tr) ... b)
(lambda (a : t)
(lambda* (ar : tr) ... b))]
[(_ b) b]))
(data and : (forall* (A : Type) (B : Type) Type)
(conj : (forall* (A : Type) (B : Type)
(x : A) (y : B) (and A B))))
;; -------------------
;; Prove interesting theorems!
(define (thm:and-is-symmetric
(x : (forall* (P : Type) (Q : Type)
;; TODO: Can't use -> for the final clause because generated
;; name has to match name in proof.
(ab : (and P Q))
(and P Q))))
T)
(define proof:and-is-symmetric
(lambda* (P : Type) (Q : Type) (ab : (and P Q))
(case ab
(conj (lambda* (P : Type) (Q : Type) (x : P) (y : Q) (conj Q P y x))))))
(define proof:and-is-symmetric^
(lambda* (S : Type) (R : Type) (ab : (and S R))
(case ab
(conj (lambda* (S : Type) (R : Type) (s : S) (r : R) (conj R S r s))))))
(check-equal? (thm:and-is-symmetric proof:and-is-symmetric) T)
(check-equal? (thm:and-is-symmetric proof:and-is-symmetric^) T)
;; -------------------
;; Gee, I wish there was a special syntax for theorems and proofs so I could think of
;; them as seperate from types and programs.
(define-syntax-rule (define-theorem name prop)
(define (name (x : prop)) T))
(define-syntax-rule (qed thm pf)
(check-equal? T (thm pf)))
(define-theorem thm:and-is-symmetric^^
(forall* (P : Type) (Q : Type) (ab : (and P Q)) (and Q P)))
(qed thm:and-is-symmetric^^ proof:and-is-symmetric)
(define-theorem thm:proj1
(forall* (A : Type) (B : Type) (c : (and A B)) A))
(define proof:proj1
(lambda* (A : Type) (B : Type) (c : (and A B))
(case c (conj (lambda* (A : Type) (B : Type) (a : A) (b : B) a)))))
(qed thm:proj1 proof:proj1)
(define-theorem thm:proj2
(forall* (A : Type) (B : Type) (c : (and A B)) B))
(define proof:proj2
(lambda* (A : Type) (B : Type) (c : (and A B))
(case c (conj (lambda* (A : Type) (B : Type) (a : A) (b : B) b)))))
(qed thm:proj2 proof:proj2)
;; -------------------
;; Gee, I wish I had special syntax for defining types like I do for
;; defining functions.
(define-syntax-rule (define-type (name (a : t) ...) body)
(define name (forall* (a : t) ... body)))
(define-type (not (A : Type)) (-> A false))
#|
;;TODO: Can't pattern match on a inductive with 0 constructors yet.
(define-theorem thm:absurd
(forall* (P : Type) (A : Type) (a : A) (~a : (not A)) P))
(qed thm:absurd (lambda* (P : Type) (A : Type) (a : A) (~a : (not A))
(case (~a a))))
(define-theorem thm:absurdidty
(forall* (P : Type) (A : Type) (a*nota : (and A (not A))) P))
;; TODO: Not sure why this doesn't type-check.. probably not handling
;; inductive families correctly in (case ...)
(define (proof:absurdidty (P : Type) (A : Type) (a*nota : (and A (not A))))
((proof:proj2 A (not A) a*nota) (proof:proj1 A (not A) a*nota)))
|#
;; -------------------
;; Automate theorem proving! With real meta-programming, syntax is just data.
(define-syntax (inhabit-type syn)
(syntax-case syn (true false nat forall :)
[(_ true) #'T]
[(_ nat) #'z]
[(_ false)
(raise-syntax-error 'inhabit
"Actually, this type is unhabited" syn)]
;; TODO: We want all forall*s to be expanded by this point. Should
;; look into Racket macro magic to expand syn before matching on it.
[(_ (forall (x : t0) t1))
;; TODO: Should carry around assumptions to enable inhabit-type to use
;; them
#'(lambda (x : t0) (inhabit-type t1))]
[(_ t)
(raise-syntax-error 'inhabit
"Sorry, this type is too much for me" syn)]))
(define-theorem thm:true-is-proveable true)
(qed thm:true-is-proveable (inhabit-type true))
(define-theorem thm:anything-implies-true (forall (P : Type) true))
(qed thm:true-is-proveable (inhabit-type (forall (P : Type) true)))
#;(define is-this-inhabited? (inhabit-type false))
;; -------------------
;; Unit test your theorems before proving them!
(define-syntax ->*
(syntax-rules ()
[(->* a) a]
[(->* a a* ...)
(-> a (->* a* ...))]))
;; TODO: Ought to have some syntactic sugar for doing this.
;; Or a different representation of theorems.
(define type-thm:true?
(forall* (A : Type) (B : Type) (P : Type)
;; If A implies P and (and A B) then P
(->* (-> A P) (and A B) P)))
(define-theorem thm:true? type-thm:true?)
(qed (lambda (x : (type-thm:true? true true true)) T)
;; TODO: inhabit-type ought to be able to reduce (type-thm:true? true true true)
;; but can't. Maybe instead there should be a reduce tactic/macro.
(inhabit-type (forall (a : (-> true true))
(forall (f : (and true true))
true))))