2025-02-20 23:11:31 -05:00
|
|
|
|
;; okay, i'll keep these procedures for the sake of nesting
|
|
|
|
|
|
2025-02-20 23:38:00 -05:00
|
|
|
|
(define (make-pand p q) `(∧ ,p ,q))
|
2025-02-20 22:26:09 -05:00
|
|
|
|
|
|
|
|
|
(define pand
|
|
|
|
|
(case-lambda
|
|
|
|
|
[() #t]
|
|
|
|
|
[(p) p]
|
2025-02-21 11:44:05 -05:00
|
|
|
|
[(p . qs) (make-pand p (apply pand qs))]))
|
2025-02-20 22:26:09 -05:00
|
|
|
|
|
2025-02-20 23:38:00 -05:00
|
|
|
|
(define (make-por p q) `(∨ ,p ,q))
|
2025-02-20 22:26:09 -05:00
|
|
|
|
|
|
|
|
|
(define por
|
|
|
|
|
(case-lambda
|
|
|
|
|
[() #f]
|
|
|
|
|
[(p) p]
|
2025-02-21 11:44:05 -05:00
|
|
|
|
[(p . qs) (make-por p (apply por qs))]))
|
2025-02-20 22:26:09 -05:00
|
|
|
|
|
|
|
|
|
;; iirc, or: (not p) or q
|
2025-02-20 23:38:00 -05:00
|
|
|
|
(define (make-p-> p q) `(→ ,p ,q))
|
2025-02-20 22:26:09 -05:00
|
|
|
|
|
|
|
|
|
;; could fold but laziness
|
|
|
|
|
(define p->
|
|
|
|
|
(case-lambda
|
|
|
|
|
[() #t]
|
|
|
|
|
[(p) p]
|
|
|
|
|
[(p . qs) (make-p-> p (apply p-> qs))]))
|
|
|
|
|
|
|
|
|
|
(define (p<-> p q) (pand (p-> p q) (p-> q p)))
|
|
|
|
|
;; maybe could have some pretty-printing logic? this definition is just 2 good 2 pass up
|
|
|
|
|
(define (pnot p) (p-> p #f))
|
|
|
|
|
(define ~ pnot)
|
|
|
|
|
|
|
|
|
|
;; maybe a var is just a sym? no forall lel
|
|
|
|
|
;; existence l8r
|
|
|
|
|
;; nah
|
|
|
|
|
;; valued vars? :o
|
|
|
|
|
|
|
|
|
|
;; (define-record-type forall
|
|
|
|
|
;; (fields vars p)
|
|
|
|
|
;; (nongenerative forall))
|
|
|
|
|
;; (define-syntax forall
|
|
|
|
|
;; (syntax-rules ()
|
|
|
|
|
;; [(forall (var* ...) p)
|
|
|
|
|
;; (make-forall
|
|
|
|
|
;; '(var* ...)
|
|
|
|
|
;; (let ([var* 'var*] ...) p))]
|
|
|
|
|
;; [(forall var p) (forall (var) p)]))
|
|
|
|
|
|
|
|
|
|
(define-record-type argument
|
2025-02-20 23:11:31 -05:00
|
|
|
|
(fields premises conclusions)
|
2025-02-20 22:26:09 -05:00
|
|
|
|
(nongenerative argument))
|
|
|
|
|
|
|
|
|
|
(define-syntax argument
|
|
|
|
|
(syntax-rules ()
|
2025-02-20 23:11:31 -05:00
|
|
|
|
[(_ (var* ...) (premise* ...) (conclusion* ...))
|
2025-02-20 22:26:09 -05:00
|
|
|
|
(lambda (var* ...)
|
2025-02-20 23:11:31 -05:00
|
|
|
|
(make-argument (list premise* ...) (list conclusion* ...)))]))
|
2025-02-20 22:26:09 -05:00
|
|
|
|
|
2025-02-21 11:44:05 -05:00
|
|
|
|
(define (argument->statement arg)
|
|
|
|
|
(apply p-> (append (argument-premises arg)
|
|
|
|
|
(list (apply pand (argument-conclusions arg))))))
|
2025-02-20 23:11:31 -05:00
|
|
|
|
|
2025-02-21 11:44:05 -05:00
|
|
|
|
(define (general-argument->statement arg)
|
|
|
|
|
(lambda ps (argument->statement (apply arg ps))))
|
2025-02-20 22:26:09 -05:00
|
|
|
|
|
|
|
|
|
;; (follows (P* ... (-> p q) p Q* ...) q modus-ponens) => #t
|
|
|
|
|
;; iterative argument
|
|
|
|
|
;; laws of inference are taken as fact
|
|
|
|
|
;; norm vars
|
|
|
|
|
;; order irrelevant
|
|
|
|
|
;; search for reqs?
|
|
|
|
|
|
|
|
|
|
(define (premises<=? p1 p2)
|
|
|
|
|
(and (andmap (lambda (prem) (member prem p2)) p1)
|
|
|
|
|
#t))
|
|
|
|
|
|
2025-02-20 23:11:31 -05:00
|
|
|
|
(define (follows? prems q by)
|
|
|
|
|
(and (member q (argument-conclusions by))
|
|
|
|
|
(premises<=? (argument-premises by) prems)))
|
2025-02-20 22:26:09 -05:00
|
|
|
|
|
2025-02-20 23:11:31 -05:00
|
|
|
|
(define-record-type step
|
|
|
|
|
(fields conclusion rule)
|
|
|
|
|
(nongenerative step))
|
2025-02-20 22:26:09 -05:00
|
|
|
|
|
2025-02-20 23:11:31 -05:00
|
|
|
|
(define-record-type proof
|
|
|
|
|
(fields argument steps)
|
|
|
|
|
(nongenerative proof))
|
2025-02-20 22:26:09 -05:00
|
|
|
|
|
2025-02-20 23:11:31 -05:00
|
|
|
|
(define-syntax proof
|
|
|
|
|
(syntax-rules ()
|
|
|
|
|
[(_ (var* ...) arg (conclusion* rule*) ...)
|
|
|
|
|
(lambda (var* ...)
|
|
|
|
|
(make-proof (arg var* ...)
|
|
|
|
|
(list (make-step conclusion* rule*) ...)))]))
|
|
|
|
|
|
|
|
|
|
;; bleh
|
|
|
|
|
;; huh, procedure-arity-mask can handle 1000+ no problem
|
|
|
|
|
;; returns the lowest arity
|
|
|
|
|
(define (procedure-arity proc)
|
|
|
|
|
(define mask (procedure-arity-mask proc))
|
|
|
|
|
(let loop ([i 0])
|
|
|
|
|
(if (logbit? i mask)
|
|
|
|
|
i
|
|
|
|
|
(loop (add1 i)))))
|
|
|
|
|
|
2025-02-20 23:38:00 -05:00
|
|
|
|
;; so over-general lel
|
|
|
|
|
(define proof-variable
|
|
|
|
|
(let* ([bases '#(p q r s t u)]
|
|
|
|
|
[bases-count (vector-length bases)])
|
|
|
|
|
(lambda (n)
|
|
|
|
|
(define base (vector-ref bases (mod n bases-count)))
|
|
|
|
|
(define num (floor (/ n bases-count)))
|
|
|
|
|
(string->symbol
|
|
|
|
|
(format "~a~a"
|
|
|
|
|
base
|
|
|
|
|
(if (zero? num) "" num))))))
|
|
|
|
|
|
2025-02-21 00:24:13 -05:00
|
|
|
|
(define (placeholder-saturate f)
|
|
|
|
|
;; map iota is bad but convenient (macro so needed)
|
|
|
|
|
(apply f (map proof-variable (iota (procedure-arity f)))))
|
|
|
|
|
|
2025-02-20 23:38:00 -05:00
|
|
|
|
;; i think i prefer the turnstile to therefore
|
|
|
|
|
(define (argument-pp arg port)
|
|
|
|
|
(define prems (argument-premises arg))
|
|
|
|
|
(define concls (argument-conclusions arg))
|
|
|
|
|
(format port "~{~a\n~}~{⊢ ~a\n~}"
|
|
|
|
|
prems concls))
|
|
|
|
|
|
2025-02-21 00:24:13 -05:00
|
|
|
|
(define (general-argument-pp arg port)
|
|
|
|
|
(argument-pp (placeholder-saturate arg) port))
|
|
|
|
|
|
|
|
|
|
(define (cartesian-exponent xs n)
|
|
|
|
|
(assert (and (integer? n) (>= n 0)))
|
|
|
|
|
(case n
|
|
|
|
|
[0 '()]
|
|
|
|
|
[1 (map list xs)]
|
|
|
|
|
[else
|
|
|
|
|
(let ([exp-1 (cartesian-exponent xs (sub1 n))])
|
|
|
|
|
(apply append
|
|
|
|
|
(map (lambda (xs2)
|
|
|
|
|
(map (lambda (x)
|
|
|
|
|
(cons x xs2))
|
|
|
|
|
xs))
|
|
|
|
|
exp-1)))]))
|
2025-02-20 23:38:00 -05:00
|
|
|
|
|
2025-02-21 11:44:05 -05:00
|
|
|
|
(define (gensyms n)
|
|
|
|
|
(let loop ([i 0]
|
|
|
|
|
[xs '()])
|
|
|
|
|
(if (>= i n)
|
2025-02-20 23:11:31 -05:00
|
|
|
|
(reverse xs)
|
2025-02-21 11:44:05 -05:00
|
|
|
|
(loop (add1 i)
|
|
|
|
|
(cons (gensym (symbol->string (proof-variable i))) xs)))))
|
|
|
|
|
|
|
|
|
|
(define (proof-valid? proof%)
|
|
|
|
|
(define proof (apply proof% (gensyms (procedure-arity proof%))))
|
2025-02-20 23:11:31 -05:00
|
|
|
|
(define arg (proof-argument proof))
|
|
|
|
|
;; reversing here lets us recover a nice order at the end
|
|
|
|
|
(define prems (reverse (argument-premises arg)))
|
|
|
|
|
(define goals (argument-conclusions arg))
|
|
|
|
|
|
2025-02-21 00:24:13 -05:00
|
|
|
|
(define (fail concl rule)
|
|
|
|
|
(printf "Failed to apply rule:\n")
|
|
|
|
|
(argument-pp rule #t)
|
|
|
|
|
(printf "Proof state:\n~{~a\n~}⊢ ~a\n"
|
|
|
|
|
(reverse prems) concl)
|
|
|
|
|
#f)
|
|
|
|
|
|
|
|
|
|
(define (handle-general-step concl rule)
|
2025-02-21 11:44:05 -05:00
|
|
|
|
(define base-targets (append prems goals))
|
2025-02-21 00:24:13 -05:00
|
|
|
|
(define targets
|
2025-02-21 11:44:05 -05:00
|
|
|
|
(apply append base-targets (map (lambda (p) (if (pair? p) (cdr p) '())) base-targets)))
|
2025-02-21 00:24:13 -05:00
|
|
|
|
(ormap
|
|
|
|
|
(lambda (ts) (follows? prems concl (apply rule ts)))
|
|
|
|
|
(cartesian-exponent targets (procedure-arity rule))))
|
|
|
|
|
|
2025-02-20 23:11:31 -05:00
|
|
|
|
(call/1cc
|
|
|
|
|
(lambda (return)
|
|
|
|
|
(for-each
|
|
|
|
|
(lambda (step)
|
2025-02-21 00:24:13 -05:00
|
|
|
|
(define concl (step-conclusion step))
|
|
|
|
|
(define rule (step-rule step))
|
|
|
|
|
(define ok?
|
|
|
|
|
(if (procedure? rule)
|
|
|
|
|
(handle-general-step concl rule)
|
|
|
|
|
(follows? prems concl rule)))
|
|
|
|
|
(if ok?
|
|
|
|
|
(set! prems (cons concl prems))
|
|
|
|
|
(begin
|
|
|
|
|
(fail concl (if (procedure? rule) (placeholder-saturate rule) rule))
|
|
|
|
|
(return #f))))
|
2025-02-20 23:11:31 -05:00
|
|
|
|
(proof-steps proof))
|
2025-02-20 23:38:00 -05:00
|
|
|
|
(when (or (member #f prems) (premises<=? goals prems))
|
2025-02-21 00:51:21 -05:00
|
|
|
|
(printf "Proof complete!\n")
|
2025-02-20 23:11:31 -05:00
|
|
|
|
(return #t))
|
2025-02-21 00:51:21 -05:00
|
|
|
|
(printf "Unsolved goals:\n~{~a\n~}~{⊢ ~a\n~}\n"
|
|
|
|
|
(reverse prems)
|
2025-02-21 11:44:05 -05:00
|
|
|
|
(filter (lambda (g) (not (member g prems))) goals))
|
|
|
|
|
#f)))
|
|
|
|
|
|
|
|
|
|
(define modus-ponens
|
|
|
|
|
(argument (p q)
|
|
|
|
|
[(p-> p q)
|
|
|
|
|
p]
|
|
|
|
|
[q]))
|
|
|
|
|
|
|
|
|
|
(define modus-tollens
|
|
|
|
|
(argument (p q)
|
|
|
|
|
[(p-> p q)
|
|
|
|
|
(~ q)]
|
|
|
|
|
[(~ p)]))
|
|
|
|
|
|
|
|
|
|
(define or.inl
|
|
|
|
|
(argument (p q)
|
|
|
|
|
[p]
|
|
|
|
|
[(por p q)]))
|
|
|
|
|
|
|
|
|
|
(define or.inr
|
|
|
|
|
(argument (p q)
|
|
|
|
|
[q]
|
|
|
|
|
[(por p q)]))
|
|
|
|
|
|
|
|
|
|
(define simplification
|
|
|
|
|
(argument (p q)
|
|
|
|
|
[(pand p q)]
|
|
|
|
|
[p q]))
|
|
|
|
|
|
|
|
|
|
(define or.eliml
|
|
|
|
|
(argument (p q)
|
|
|
|
|
[(por p q)
|
|
|
|
|
(~ p)]
|
|
|
|
|
[q]))
|
|
|
|
|
|
|
|
|
|
(define or.elimr
|
|
|
|
|
(argument (p q)
|
|
|
|
|
[(por p q)
|
|
|
|
|
(~ q)]
|
|
|
|
|
[p]))
|
|
|
|
|
|
|
|
|
|
(define conjunction
|
|
|
|
|
(argument (p q)
|
|
|
|
|
[p
|
|
|
|
|
q]
|
|
|
|
|
[(pand p q)]))
|
|
|
|
|
|
|
|
|
|
(define transitivity
|
|
|
|
|
(argument (p q r)
|
|
|
|
|
[(p-> p q)
|
|
|
|
|
(p-> q r)]
|
|
|
|
|
[(p-> p r)]))
|
|
|
|
|
|
|
|
|
|
(define cases
|
|
|
|
|
(argument (p q r)
|
|
|
|
|
[(por p q)
|
|
|
|
|
(p-> p r)
|
|
|
|
|
(p-> q r)]
|
|
|
|
|
[r]))
|
2025-02-20 23:11:31 -05:00
|
|
|
|
|
2025-02-21 00:51:21 -05:00
|
|
|
|
;; TODO: this really isn't far from the macroless version....
|
2025-02-20 23:11:31 -05:00
|
|
|
|
(define and-comm
|
|
|
|
|
(proof (p q)
|
|
|
|
|
(argument (p q)
|
|
|
|
|
[(pand p q)]
|
|
|
|
|
[(pand q p)])
|
|
|
|
|
[p (simplification p q)]
|
|
|
|
|
[q (simplification p q)]
|
|
|
|
|
[(pand q p) (conjunction q p)]))
|
2025-02-20 22:26:09 -05:00
|
|
|
|
|
2025-02-21 00:24:13 -05:00
|
|
|
|
(define and-comm-ez
|
|
|
|
|
(proof (p q)
|
|
|
|
|
(argument (p q)
|
|
|
|
|
[(pand p q)]
|
|
|
|
|
[(pand q p)])
|
|
|
|
|
[p simplification]
|
|
|
|
|
[q simplification]
|
|
|
|
|
[(pand q p) conjunction]))
|
2025-02-21 00:51:21 -05:00
|
|
|
|
|
|
|
|
|
;; TODO: make this expressible better
|
|
|
|
|
;; TODO: use proofs for other proofs nicely
|
|
|
|
|
;; the mismatch between what is written and what is shown is hideous
|
|
|
|
|
;; avoidable by being explicit ig
|
2025-02-21 11:44:05 -05:00
|
|
|
|
(define and-assoc.mp
|
2025-02-21 00:51:21 -05:00
|
|
|
|
(proof (p q r)
|
|
|
|
|
(argument (p q r)
|
|
|
|
|
[(pand p (pand q r))]
|
|
|
|
|
[(pand (pand p q) r)])
|
|
|
|
|
[p simplification]
|
|
|
|
|
[(pand q r) simplification]
|
|
|
|
|
[q simplification]
|
|
|
|
|
[r simplification]
|
|
|
|
|
[(pand p q) conjunction]
|
|
|
|
|
[(pand (pand p q) r) conjunction]))
|
|
|
|
|
|
2025-02-21 11:44:05 -05:00
|
|
|
|
(proof-valid? and-assoc.mp)
|