diff options
| -rw-r--r-- | vikalpa.scm | 1645 | 
1 files changed, 1645 insertions, 0 deletions
| diff --git a/vikalpa.scm b/vikalpa.scm new file mode 100644 index 0000000..eadd2a0 --- /dev/null +++ b/vikalpa.scm @@ -0,0 +1,1645 @@ +;;; Vikalpa --- Proof Assistant +;;; Copyright © 2020, 2021 Masaya Tojo <masaya@tojo.tokyo> +;;; +;;; This file is part of Vikalpa. +;;; +;;; Vikalpa is free software; you can redistribute it and/or modify it +;;; under the terms of the GNU General Public License as published by +;;; the Free Software Foundation; either version 3 of the License, or +;;; (at your option) any later version. +;;; +;;; Vikalpa is distributed in the hope that it will be useful, but +;;; WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +;;; General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with Vikalpa.  If not, see <http://www.gnu.org/licenses/>. + +(define-module (vikalpa) +  #:export (system? +            system-rewrite +            system-check +            system-apropos +            system-eval +            system-lookup +            set-measure-predicate +            set-measure-less-than +            define-system +            define-proof +            define-core-function +            define-core-function/guard +            define-function +            define-function +            define-function/guard +            define-axiom-function +            define-axiom-function/guard +            define-syntax-rules +            define-axiom +            define-theorem +            define-guard-theorem +            admit) +  #:use-module (ice-9 match) +  #:use-module (ice-9 format) +  #:use-module (ice-9 control) +  #:use-module (ice-9 exceptions) +  #:use-module (ice-9 regex) +  #:use-module ((srfi srfi-1) +                #:select (every any lset-union fold append-map find +                                filter-map)) +  #:use-module (srfi srfi-8) +  #:use-module (srfi srfi-11) +  #:use-module (srfi srfi-26) +  #:use-module (oop goops)) + +(define-class <system> () +  (definitions +    #:getter get-definitions +    #:init-keyword #:definitions +    #:init-value '()) +  (measure-predicate #:getter get-measure-predicate +                     #:init-value #f) +  (measure-less-than #:getter get-measure-less-than +                     #:init-value #f)) + +(define-class <definition> () +  (name #:getter get-name +        #:init-keyword #:name) +  (variables #:getter get-variables +             #:init-keyword #:variables +             #:init-value '())) + +(define-class <provable> ()) + +(define-class <proved> (<provable>) +  (claim #:getter get-claim #:init-keyword #:claim) +  (proof #:getter get-proof #:init-keyword #:proof)) + +(define-class <admitted> ()) + +(define-class <theorem*> (<definition>) +  (expression #:getter get-expression #:init-keyword #:expression)) + +(define-class <conjecture> (<theorem*> <provable>)) +(define-class <theorem> (<theorem*> <proved>)) +(define-class <axiom> (<theorem*>)) +(define-class <admitted-theorem> (<theorem*> <proved> <admitted>)) + +(define-class <function*> (<definition>) +  (guards #:getter get-guards #:init-keyword #:guards)) +(define-class <core-function> (<function*>) +  (procedure #:getter get-procedure #:init-keyword #:procedure)) +(define-class <expandable-function> (<function*>) +  (expression #:getter get-expression #:init-keyword #:expression) +  (code #:getter get-code #:init-keyword #:code)) +(define-class <function> (<expandable-function> <provable>)) +(define-class <total-function> (<expandable-function> <proved>)) +(define-class <admitted-function> (<expandable-function> <proved> <admitted>)) + +(define-class <macro> (<definition>) +  (mrules #:getter macro-mrules #:init-keyword #:mrules) +  (literals #:getter macro-literals #:init-keyword #:literals)) + +(define (write-definition sym d port) +  (format port "#<~a: ~s>" +          sym (cons (get-name d) (get-variables d)))) + +(define-method (display (s <system>) port) +  (format port "#<system: function: ~a theorem: ~a macro: ~a>" +          (length (filter (cut is-a? <> <function*>) +                          (get-definitions s))) +          (length (filter (cut is-a? <> <theorem*>) +                          (get-definitions s))) +          (length (filter (cut is-a? <> <macro>) +                          (get-definitions s))))) + +(define-method (write (s <system>) port) +  (format port "#<system: function: ~a theorem: ~a macro: ~a>" +          (length (filter (cut is-a? <> <function*>) +                          (get-definitions s))) +          (length (filter (cut is-a? <> <theorem*>) +                          (get-definitions s))) +          (length (filter (cut is-a? <> <macro>) +                          (get-definitions s))))) + +(define-method (lookup name (s <system>)) +  (find (lambda (x) +          (equal? name (get-name x))) +        (get-definitions s))) + +(define-method (update-measure-predicate (s <symbol>) (sys <system>)) +  (let ((new (shallow-clone sys))) +    (slot-set! new 'measure-predicate s) +    new)) + +(define-method (update-measure-less-than (s <symbol>) (sys <system>)) +  (let ((new (shallow-clone sys))) +    (slot-set! new 'measure-less-than s) +    new)) + +(define-method (update-definition (d <definition>) (sys <system>)) +  (define (update d defs) +    (if (null? defs) +        (raise-exception +         (make-exception +          (make-exception-with-origin 'update-definition) +          (make-exception-with-message "not found") +          (make-exception-with-irritants (list d defs)))) +        (if (equal? (get-name d) (get-name (car defs))) +            (cons d (cdr defs)) +            (cons (car defs) (update d (cdr defs)))))) +  (let ((new (shallow-clone sys))) +    (slot-set! new 'definitions +               (update d (get-definitions sys))) +    new)) + +(define-method (remove-first-definition (sys <system>)) +  (let ((new (shallow-clone sys))) +    (slot-set! new 'definitions +               (cdr (get-definitions sys))) +    new)) + +(define-method (first-definition (sys <system>)) +  (car (get-definitions sys))) + +(define-method (system-empty? (sys <system>)) +  (null? (get-definitions sys))) + +(define-method (add-definition (d <definition>) (s <system>)) +  (if (lookup (get-name d) s) +      (raise-exception +       (make-exception +        (make-exception-with-origin 'add-definition) +        (make-exception-with-message "duplicated definition") +        (make-exception-with-irritants (get-name d)))) +      (if (reserved? (get-name d)) +          (raise-exception +           (make-exception +            (make-exception-with-origin 'add-definition) +            (make-exception-with-message "reserved name") +            (make-exception-with-irritants (get-name d)))) +          (let ((new (shallow-clone s))) +            (slot-set! new 'definitions +                       (cons d (get-definitions s))) +            new)))) + +(define-method (validate (d <definition>)) +  (let* ((vars (get-variables d)) +         (name (get-name d))) +    (validate-vars (format #f "~a" name) vars))) + +(define-method (validate (d <expandable-function>)) +  (let* ((vars (get-variables d)) +         (name (get-name d)) +         (expr (get-expression d))) +    (validate-expression (current-system) name vars expr) +    (next-method))) + +(define-method (validate (d <theorem*>)) +  (let* ((vars (get-variables d)) +         (name (get-name d)) +         (expr (get-expression d))) +    (validate-expression (current-system) name vars expr) +    (next-method))) + +(define-syntax-rule (define/guard (name (var p?) ...) b b* ...) +  (define (name var ...) +    (unless (p? var) +      (error (format #f +                     "~a:~%  expected:  ~a~%  given: " +                     'name +                     'p?) +             var)) +    ... +    b b* ...)) + +(define (natural? x) +  (and (exact-integer? x) +       (not (negative? x)))) + +(define (option p?) +  (lambda (x) +    (or (p? x) (not x)))) + +(define (list-of p?) +  (lambda (x) +    (and (list? x) +         (every p? x)))) + +(define (expression? expr) +  (cond ((expr-quoted? expr) #t) +        ((if-form? expr) +         (and (expression? (if-form-test expr)) +              (expression? (if-form-then expr)) +              (expression? (if-form-else expr)))) +        ((app-form? expr) +         (and (symbol? (car expr)) +              (list? (cdr expr)) +              (every expression? (cdr expr)))) +        ((variable? expr) #t) +        (else #f))) + +(define (app-form? expr) +  (and (pair? expr) +       (not (eq? (car expr) 'quote)) +       (not (eq? (car expr) 'if)))) + +(define (app-form name args) +  (cons name args)) + +(define (app-form-name expr) +  (car expr)) + +(define (app-form-args expr) +  (cdr expr)) + +(define (if-form test then else) +  (list 'if test then else)) + +(define (if-form? x) +  (and (pair? x) +       (eq? (car x) 'if))) + +(define (if-form-test expr) +  (list-ref expr 1)) + +(define (if-form-then expr) +  (list-ref expr 2)) + +(define (if-form-else expr) +  (list-ref expr 3)) + +(define (expression-app-forms expr) +  (cond +   ((if-form? expr) +    (append-map expression-app-forms +                (list (if-form-test expr) +                      (if-form-then expr) +                      (if-form-else expr)))) +   ((app-form? expr) +    (cons expr +          (append-map expression-app-forms +                      (app-form-args expr)))) +   (else '()))) + +(define (expression-functions expr) +  (cond +   ((if-form? expr) +    (apply lset-union +           eq? +           (map expression-functions +                (list (if-form-test expr) +                      (if-form-then expr) +                      (if-form-else expr))))) +   ((app-form? expr) +    (cons (app-form-name expr) +          (apply lset-union +                 eq? +                 (map expression-functions (app-form-args expr))))) +   (else '()))) + +(define (expression-vars expr) +  (cond +   ((expr-quoted? expr) '()) +   ((if-form? expr) +    (lset-union eq? +                (expression-vars (if-form-test expr)) +                (expression-vars (if-form-then expr)) +                (expression-vars (if-form-else expr)))) +   ((app-form? expr) +    (apply lset-union +           eq? +           (map expression-vars (app-form-args expr)))) +   ((variable? expr) (list expr)) +   (else '()))) + +(define (expr-quoted? expr) +  (and (pair? expr) +       (eq? 'quote (car expr)) +       (pair? (cdr expr)) +       ((const #t) (car (cdr expr))) +       (null? (cdr (cdr expr))))) + +(define (expr-unquote expr) +  (car (cdr expr))) + +(define (expr-quote expr) +  (list 'quote expr)) + +(define (variable? x) +  (symbol? x)) + +(define (variable=? v1 v2) +  (eq? v1 v2)) + +(define-class <rule> () +  (vars #:getter rule-vars #:init-keyword #:vars) +  (preconds #:getter rule-preconds #:init-keyword #:preconds) +  (lhs #:getter rule-lhs #:init-keyword #:lhs) +  (rhs #:getter rule-rhs #:init-keyword #:rhs)) + +(define (rule var preconds lhs rhs) +  (make <rule> +    #:vars var +    #:preconds preconds +    #:lhs lhs +    #:rhs rhs)) + +(define (rule? x) +  (is-a? x <rule>)) + +(define (binding? x) +  (and (pair? x) +       (symbol? (car x)) +       (expression? (cdr x)))) + +(define (env? x) +  ((list-of binding?) x)) + +(define/guard (substitute (env env?) (expr (const #t))) +  (cond ((expr-quoted? expr) expr) +        ((pair? expr) +         (cons (substitute env (car expr)) +               (substitute env (cdr expr)))) +        ((assoc expr env) => cdr) +        (else expr))) + +(define (match-rule preconds rl expr env) +  (define (fail) +    (shift k #f)) +  (define (var? v) +    (and (member v (rule-vars rl)) +         #t)) +  (define (add-env var expr env) +    (cond +     ((assoc var env) +      => (match-lambda +           ((env-var . env-expr) +            (if (equal? env-expr expr) +                env +                (fail))))) +     (else +      (cons (cons var expr) +            env)))) +  (define (mat-fold lhss exprs env) +    (cond ((and (pair? lhss) (pair? exprs)) +           (mat-fold (cdr lhss) +                     (cdr exprs) +                     (mat (car lhss) +                          (car exprs) +                          env))) +          ((and (null? lhss) (null? exprs)) env) +          (else (fail)))) +  (define (mat-begin lhs expr env) +    (reset (mat lhs expr env))) +  (define (mat lhs expr env) +    (cond ((expr-quoted? lhs) +           (if (expr-quoted? expr) +               (if (equal? lhs expr) +                   env +                   (fail)) +               (fail))) +          ((and (if-form? lhs) +                (if-form? expr)) +           (mat-fold (list (if-form-test lhs) +                           (if-form-then lhs) +                           (if-form-else lhs)) +                     (list (if-form-test expr) +                           (if-form-then expr) +                           (if-form-else expr)) +                     env)) +          ((app-form? lhs) +           (if (and (app-form? expr) +                    (symbol? (app-form-name lhs)) +                    (eqv? (app-form-name lhs) (app-form-name expr))) +               (mat-fold (app-form-args lhs) (app-form-args expr) env) +               (fail))) +          ((var? lhs) (add-env lhs expr env)) +          (else (fail)))) +  (define (mat-preconds rlps k+env) +    (if (null? rlps) +        k+env +        (mat-preconds +         (cdr rlps) +         (let search ((ps preconds)) +           (if (null? ps) +               (shift k ((car k+env) #f)) +               (let ((env (mat-begin (car rlps) (car ps) (cdr k+env)))) +                 (cond +                  ((mat-begin (car rlps) (car ps) (cdr k+env)) +                   => (lambda (env) +                        (shift k0 +                               (reset +                                (or (shift k (k0 (cons k env))) +                                    (k0 (search (cdr ps)))))))) +                  (else (search (cdr ps)))))))))) +  (define (valid? env expr) +    (cond ((expr-quoted? expr) #t) +          ((pair? expr) +           (and (valid? env (car expr)) +                (valid? env (cdr expr)))) +          ((var? expr) +           (cond ((assoc expr env) => (const #t)) +                 (else #f))) +          (else #t))) +  (reset +   (shift k0 +          (match (mat-preconds (rule-preconds rl) (cons k0 env)) +            ((k . env) +             (cond +              ((mat-begin (rule-lhs rl) expr env) +               => (lambda (env) +                    (if (valid? env (rule-rhs rl)) +                        env +                        (k #f)))) +              (else (k #f)))) +            (else #f))))) + +(define (apply-rule preconds rl expr env) +  (cond +   ((match-rule preconds rl expr env) +    => (cut substitute <> (rule-rhs rl))) +   (else #f))) + +(define (code x) +  (list 'code x)) + +(define (code-expr x) +  (cadr x)) + +(define-class <mrule> () +  (lhs #:getter mrule-lhs #:init-keyword #:lhs) +  (rhs #:getter mrule-rhs #:init-keyword #:rhs)) + +(define (mrule lhs rhs) +  (make <mrule> #:lhs lhs #:rhs rhs)) + +(define (mrule-vars mrl) +  (define (all-vars x) +    (cond ((expr-quoted? x) '()) +          ((pair? x) +           (append (all-vars (car x)) +                   (all-vars (cdr x)))) +          ((variable? x) (list x)) +          (else '()))) +  (all-vars (mrule-lhs mrl))) + +(define (macro name mrules literals) +  (make <macro> +    #:name name +    #:variables '() +    #:mrules mrules +    #:literals literals)) + +(define (apply-mrule rl ls expr) +  (define (literal? x) +    (member x ls)) +  (define (var? v) +    (and (member v (mrule-vars rl)) +         #t)) +  (call/cc +   (lambda (k) +     (define (mat-map lhs-tree expr-tree env) +       (cond ((and (pair? lhs-tree) +                   (pair? expr-tree)) +              (mat-map (car lhs-tree) +                       (car expr-tree) +                       (mat-map (cdr lhs-tree) +                                (cdr expr-tree) +                                env))) +             (else (mat lhs-tree expr-tree env)))) +     (define (mat lhs expr env) +       (cond ((expr-quoted? lhs) +              (if (expr-quoted? expr) +                  (if (equal? lhs expr) +                      env +                      (k #f)) +                  (k #f))) +             ((and (pair? lhs) (pair? expr)) +              (mat-map lhs expr env)) +             ((literal? lhs) +              (if (eq? lhs expr) +                  env +                  (k #f))) +             ((var? lhs) +              (cond +               ((assoc lhs env) +                => (match-lambda +                     ((env-var . env-expr) +                      (if (equal? env-expr expr) +                          env +                          (k #f))))) +               (else +                (cons (cons lhs expr) +                      env)))) +             ((eqv? lhs expr) env) +             (else (k #f)))) +     (define (mrule-substitute env expr) +       (cond ((expr-quoted? expr) expr) +             ((pair? expr) +              (cons (mrule-substitute env (car expr)) +                    (mrule-substitute env (cdr expr)))) +             ((literal? expr) expr) +             ((and (variable? expr) (assoc expr env)) => cdr) +             (else expr))) +     (mrule-substitute (mat (mrule-lhs rl) +                            expr +                            '()) +                       (mrule-rhs rl))))) + +(define (apply-macro m expr) +  (cond ((and (pair? expr) +              (eq? (get-name m) (car expr))) +         (let loop ((rs (macro-mrules m))) +           (cond ((null? rs) +                  (error "(vikalpa) macro fail" m expr)) +                 ((apply-mrule (car rs) (macro-literals m) expr) => identity) +                 (else (loop (cdr rs)))))) +        (else #f))) + +(define (expand ms expr) +  (let loop ((ms ms) +             (expr expr)) +    (cond +     ((null? ms) expr) +     (else +      (expand (cdr ms) +              (cond +               ((apply-macro (car ms) expr) => identity) +               (else expr))))))) + +(define (expand* ms expr) +  (let loop ((ms ms) +             (expr expr)) +    (let ((new-expr (expand ms expr))) +      (if (equal? expr new-expr) +          (if (pair? new-expr) +              (cons (expand* ms (car new-expr)) +                    (expand* ms (cdr new-expr))) +              new-expr) +          (expand* ms new-expr))))) + +(define (quote-all x) +  (cond +   ((null? x) x) +   ((expr-quoted? x) x) +   ((pair? x) +    (cons (quote-all (car x)) +          (quote-all (cdr x)))) +   ((symbol? x) x) +   (else `',x))) + +(define (let? x) +  (and (list? x) +       (= 3 (length x)) +       (eq? 'let (list-ref x 0)) +       ((list-of (lambda (x) +                   (and (list? x) +                        (= 2 (length x)) +                        (symbol? (car x))))) +        (list-ref x 1)))) + +(define (expand-let x) +  (define (let-substitute env expr) +    (cond ((expr-quoted? expr) expr) +          ((let? expr) +           (let-substitute +            (append (map (lambda (binding) +                           (cons (car binding) +                                 (let-substitute env +                                                 (cadr binding)))) +                         (list-ref expr 1)) +                    env) +            (list-ref expr 2))) +          ((pair? expr) +           (cons (let-substitute env (car expr)) +                 (let-substitute env (cdr expr)))) +          ((assoc expr env) => cdr) +          (else expr))) +  (cond +   ((expr-quoted? x) x) +   ((let? x) +    (expand-let +     (let-substitute (map (lambda (binding) (cons (car binding) +                                                  (cadr binding))) +                          (list-ref x 1)) +                     (list-ref x 2)))) +   ((pair? x) +    (cons (expand-let (car x)) +          (expand-let (cdr x)))) +   (else x))) + +(define (convert-to-expression x) +  (quote-all +   (expand* (filter (cut is-a? <> <macro>) +                    (get-definitions (current-system))) +            (expand-let x)))) + +(define (vars? x) +  (and (list? x) +       (every variable? x))) + +(define (theorem-rules x) +  (expression->rules (get-variables x) +                     '() +                     (get-expression x))) + +(define (result? x) +  (or (result/error? x) +      (result/expr? x))) + +(define (result/error? x) +  (and (pair? x) +       (eq? 'result/error (car x)))) + +(define (result/error . args) +  (cons* 'result/error args)) + +(define (result/expr? x) +  (and (list? x) +       (= 2 (length x)) +       (eq? 'result/expr (car x)) +       (expression? (cadr x)))) + +(define (result/expr x) +  (list 'result/expr x)) + +(define/guard (result/expr-expr (x result/expr?)) +  (cadr x)) + +(define (rewrite/eval expr sys) +  (let eval ((result (result/expr expr))) +    (cond +     ((result/error? result) result) +     ((result/expr? result) +      (let ((expr (result/expr-expr result))) +        (cond +         ((expr-quoted? expr) (result/expr expr)) +         ((app-form? expr) +          (let ((args/result (map (compose eval result/expr) +                                  (app-form-args expr))) +                (name (app-form-name expr))) +            (cond +             ((find error? args/result) => identity) +             ((lookup name sys) +              => (lambda (f) +                   (let ((args (map result/expr-expr args/result)) +                         (gs (get-guards f)) +                         (vars (get-variables f)) +                         (form (defined-function-app-form f))) +                     (define (guard-ok? vars form g) +                       (let ((result (eval (apply-rule '() +                                                       (rule vars '() form g) +                                                       `(,name ,@args) +                                                       '())))) +                         (if (result/error? result) +                             result +                             (expr-unquote (result/expr-expr result))))) +                     (if (every (lambda (g) (guard-ok? vars form g)) gs) +                         (eval (rewrite1 sys +                                         `(,name ,@args) +                                         `(rewrite () ,name))) +                         (result/error 'guard-error `(,name ,@args) `(and ,@gs)))))) +             (else (result/error 'function-not-found name))))) +         ((if-form? expr) +          (let ((test/result (eval (result/expr (if-form-test expr))))) +            (if (result/error? test/result) +                test/result +                (if (expr-unquote (result/expr-expr test/result)) +                    (eval (result/expr (if-form-then expr))) +                    (eval (result/expr (if-form-else expr))))))) +         ((variable? expr) +          (result/error 'eval 'variable-found expr)) +         (else +          (result/error 'eval 'invalid-expression expr))))) +     (else (result/error 'eval 'invalid-result result))))) + +(define (rewriter? x) +  (match x +    (('rewrite path command-name command-ops ...) +     (and (path? path) +          (command-name? command-name) +          (every command-option? command-ops))) +    (('eval path) (path? path)) +    #; +    (('induction path (fname vars ...)) +     (and (path? path) +          (symbol? fname) +          (every variable? vars))) +    (else #f))) + +(define (sequence? x) +  (and (list? x) +       (every rewriter? x))) + +(define (path? x) +  (and (list? x) +       (every natural? x))) + +(define (command-name? x) #t) + +(define (command-option? x) +  (and (pair? x) +       (case (car x) +         ((set) (and (list? x) +                     (= 3 (length x)) +                     (variable? (list-ref x 1)) +                     (expression? (list-ref x 2)))) +         (else #f)))) + +(define (command-name x) +  (car x)) + +(define (command-options x) +  (cdr x)) + +(define/guard (system-eval (sys system?) (expr (const #t))) +  (rewrite/eval (parameterize ((current-system sys)) +                  (convert-to-expression expr)) +                sys)) + +(define (extract path expr fail) +  (if (null? path) +      (values expr '() identity) +      (let ((i (car path))) +        (cond +         ((if-form? expr) +          (let ((precond (if-form-test expr))) +            (receive (extracted-expr preconds builder) +                (extract (cdr path) (list-ref expr i) fail) +              (values extracted-expr +                      (case i +                        ((1) preconds) +                        ((2) (cons (prop-not (prop-not precond)) +                                   preconds)) +                        ((3) (cons (prop-not precond) preconds)) +                        (else (fail 'if-invaild-path path))) +                      (lambda (x) +                        (append (list-head expr i) +                                (list (builder x)) +                                (list-tail expr (+ i 1)))))))) +         ((< i (length expr)) +          (receive (extracted-expr preconds builder) +              (extract (cdr path) (list-ref expr i) fail) +            (values extracted-expr +                    preconds +                    (lambda (x) +                      (append (list-head expr i) +                              (list (builder x)) +                              (list-tail expr (+ i 1))))))) +         (else +          (fail 'invalid-path path)))))) + +(define (function->rules x) +  (list (rule (get-variables x) +              (list) +              (defined-function-app-form x) +              (get-expression x)) +        (rule (get-variables x) +              (list) +              (get-expression x) +              (defined-function-app-form x)))) + +(define (apply-function f args) +  (apply-rule '() +              (rule (get-variables f) +                    '() +                    (defined-function-app-form f) +                    (get-expression f)) +              (app-form (get-name f) args) +              '())) + +(define (parse-options/theorem ops fail) +  (if (null? ops) +      (values '()) +      (receive (env) +          (parse-options/theorem (cdr ops) fail) +        (case (caar ops) +          ((set) +           (let ((op (car ops))) +             (cons (cons (list-ref op 1) +                         (list-ref op 2)) +                   env))) +          (else +           (fail 'invalid-option (car ops))))))) + +(define (rewrite/theorem cmd-name cmd-ops b thm preconds expr) +  (call/cc +   (lambda (k) +     (define (fail . args) +       (k (apply result/error args))) +     (receive (env) +         (parse-options/theorem cmd-ops fail) +       (cond +        ((any (cut apply-rule preconds <> expr env) +              (theorem-rules thm)) => result/expr) +        (else +         (result/error 'apply-theorem cmd-name expr))))))) + +(define (rewrite/core-function sys f expr) +  (if (and (app-form? expr) +           (eq? (get-name f) (app-form-name expr)) +           (= (length (get-variables f)) (length (app-form-args expr))) +           (every expr-quoted? (app-form-args expr))) +      (result/expr +       (expr-quote (apply (get-procedure f) +                          (map expr-unquote (app-form-args expr))))) +      (result/error 'apply-core-function (get-name f) expr))) + +(define (rewrite/function sys fname f expr) +  (cond +   ((any (cut apply-rule '() <> expr '()) +         (function->rules f)) +    => result/expr) +   (else +    (result/error 'apply-function fname expr)))) + +(define (rewrite1 sys expr r) +  (call/cc +   (lambda (k) +     (define (fail . args) +       (k (apply result/error args))) +     (define (result->expr x) +       (cond +        ((result/error? x) (fail (cdr x))) +        (else +         (result/expr-expr x)))) +     (match r +       (('eval path) +        (receive (extracted-expr preconds builder) +            (extract path expr fail) +          (result/expr +           (builder +            (result->expr (rewrite/eval extracted-expr sys)))))) +       #; +       (('induction path (fname vars ...)) +        (receive (extracted-expr preconds builder) +            (extract path expr fail) +          (result/expr +           (builder +            (result->expr +             (rewrite/induction sys fname vars preconds extracted-expr)))))) +       (('rewrite path cmd-name cmd-ops ...) +        (receive (extracted-expr preconds builder) +            (extract path expr fail) +          (result/expr +           (builder +            (result->expr +             (cond +              ((lookup cmd-name sys) +               => (lambda (x) +                    (cond +                     ((is-a? x <core-function>) +                      (rewrite/core-function sys x extracted-expr)) +                     ((is-a? x <theorem*>) +                      (rewrite/theorem cmd-name cmd-ops sys x preconds extracted-expr)) +                     ((is-a? x <expandable-function>) +                      (rewrite/function sys cmd-name x extracted-expr)) +                     (else +                      (result/error 'invalid-command cmd-name extracted-expr))))) +              (else (result/error 'command-not-found cmd-name extracted-expr)))))))))))) + +(define (rewrite sys expr seq) +  (let loop ((result (result/expr expr)) +             (seq seq)) +    (cond +     ((result/error? result) result) +     ((result/expr? result) +      (if (null? seq) +          result +          (loop (rewrite1 sys +                          (result/expr-expr result) +                          (car seq)) +                (cdr seq)))) +     (else (result/error 'invalid-result result))))) + +(define (expr-not x) +  (list 'not x)) + +(define (prop-not x) +  (match x +    (('not ('not expr)) (prop-not expr)) +    (('not expr) expr) +    (expr (expr-not expr)))) + +(define (expr-equal? x) +  (and (list? x) +       (= 3 (length x)) +       (eq? 'equal? (list-ref x 0)) +       (expression? (list-ref x 1)) +       (expression? (list-ref x 2)))) + +(define (expr-equal-lhs x) +  (list-ref x 1)) + +(define (expr-equal-rhs x) +  (list-ref x 2)) + +(define (expression->rules vars preconds expr) +  (if (if-form? expr) +      (append (expression->rules vars +                                 (cons (prop-not +                                        (prop-not +                                         (if-form-test expr))) +                                       preconds) +                                 (if-form-then expr)) +              (expression->rules vars +                                 (cons (prop-not (if-form-test expr)) +                                       preconds) +                                 (if-form-else expr)) +              (expression->rules vars +                                 preconds +                                 (if-form-test expr))) +      (if (expr-equal? expr) +          (list (rule vars +                      preconds +                      (expr-equal-lhs expr) +                      (expr-equal-rhs expr)) +                (rule vars +                      preconds +                      (expr-equal-rhs expr) +                      (expr-equal-lhs expr))) +          '()))) + +(define (theorem->rules def) +  (expression->rules (get-variables def) +                     '() +                     (get-expression def))) + +(define current-system (make-parameter (make <system>))) +(define reserved-symbols '(quote let if error)) +(define (reserved? x) +  (member x reserved-symbols)) + +(define-syntax define-axiom +  (syntax-rules () +    ((_ name (var ...) expr) +     (let ((t (make <axiom> +                #:name 'name +                #:variables '(var ...) +                #:expression (convert-to-expression 'expr)))) +       (current-system (add-definition t (current-system))) +       (validate t) +       t)))) + +(define-syntax define-theorem +  (syntax-rules () +    ((_ name (var ...) expr) +     (match 'name +       (`(guard . ,_) +        (raise-exception (make-exception +                          (make-exception-with-origin "define-theorem") +                          (make-exception-with-message "invalid theorem name (guard _ ...)") +                          (make-exception-with-irritants 'name)))) +       (else +        (let ((t (make <conjecture> +                   #:name 'name +                   #:variables '(var ...) +                   #:expression (convert-to-expression 'expr)))) +          (current-system (add-definition t (current-system))) +          (validate t) +          t)))))) + +(define (add-guard-theorem name sys) +  (cond +   ((lookup name sys) +    => (lambda (f) +         (if (is-a? f <expandable-function>) +             (add-definition (make <conjecture> +                               #:name `(guard ,name) +                               #:variables (get-variables f) +                               #:expression (fold smart-implies +                                                  (make-guard-claim +                                                   (get-expression f) +                                                   sys) +                                                  (get-guards f))) +                             sys) +             (raise-exception +              (make-exception +               (make-exception-with-origin 'define-guard-theorem) +               (make-exception-with-message "not expandable function") +               (make-exception-with-irritants name)))))) +   (else +    (raise-exception +              (make-exception +               (make-exception-with-origin 'define-guard-theorem) +               (make-exception-with-message "not found") +               (make-exception-with-irritants name)))))) + +(define-syntax define-guard-theorem +  (syntax-rules () +    ((_ name) +     (current-system (add-guard-theorem 'name (current-system)))))) + +(define-syntax define-core-function/guard +  (syntax-rules (and) +    ((_ name (var ...) (and guard ...) proc) +     (let ((f (make <core-function> +                #:name 'name +                #:variables '(var ...) +                #:guards (map convert-to-expression (list 'guard ...)) +                #:procedure proc))) +       (current-system (add-definition f (current-system))) +       (validate f) +       f)) +    ((_ name (var ...) guard proc) +     (define-core-function/guard name (var ...) (and guard) proc)))) + +(define-syntax define-core-function +  (syntax-rules () +    ((_ name (var ...) proc) +     (define-core-function/guard name (var ...) (and) proc)))) + +(define (recursive? f) +  (member (get-name f) (expression-functions (get-expression f)))) + +(define-syntax define-function/guard +  (syntax-rules (and) +    ((_ name (var ...) (and guard-expr ...) expr) +     (let* ((expression (convert-to-expression 'expr)) +            (guard-expressions (map convert-to-expression +                                    (list 'guard-expr ...))) +            (f (make <function> +                 #:name 'name +                 #:variables '(var ...) +                 #:guards guard-expressions +                 #:expression expression +                 #:code (code 'expr)))) +       (current-system (add-definition f (current-system))) +       (validate f) +       (when (not (recursive? f)) +         (let ((g (make <total-function> +                    #:name (get-name f) +                    #:variables (get-variables f) +                    #:guards (get-guards f) +                    #:expression (get-expression f) +                    #:code (get-code f) +                    #:claim ''#t +                    #:proof '()))) +           (current-system (update-definition g (current-system))) +           (validate g))) +       )) +    ((_ name (var ...) guard expr) +     (define-function/guard name (var ...) (and guard) expr)))) + +(define-syntax define-function +  (syntax-rules () +    ((_ name (var ...) expr) +     (define-function/guard name (var ...) (and) expr)))) + +(define-syntax define-syntax-rules +  (syntax-rules () +    ((_ name (l ...) ((lhs1 . lhs2) rhs) ...) +     (let ((m (macro 'name +                (list (mrule '(lhs1 . lhs2) 'rhs) +                      ...) +                '(l ...)))) +       (current-system (add-definition m (current-system))) +       m)))) + +(define-syntax admit +  (syntax-rules (and) +    ((_ name) +     (cond +      ((lookup 'name (current-system)) +       => (lambda (d) +            (unless (or (is-a? d <conjecture>) +                        (is-a? d <function>)) +              (raise-exception +               (make-exception +                (make-exception-with-origin 'name) +                (make-exception-with-message "not provable definition") +                (make-exception-with-irritants 'name)))) +            (let ((g (if (is-a? d <conjecture>) +                         (make <admitted-theorem> +                           #:name (get-name d) +                           #:variables (get-variables d) +                           #:expression (get-expression d) +                           #:claim ''#t +                           #:proof '()) +                         (make <admitted-function> +                           #:name (get-name d) +                           #:variables (get-variables d) +                           #:guards (get-guards d) +                           #:expression (get-expression d) +                           #:code (get-code d) +                           #:claim ''#t +                           #:proof '())))) +              (validate g) +              (current-system (update-definition g (current-system)))))) +      (else +       (raise-exception +        (make-exception +         (make-exception-with-origin 'name) +         (make-exception-with-message "not found") +         (make-exception-with-irritants 'name)))))))) + +(define* (core-system #:optional (parent (make <system>))) +  (parameterize ((current-system parent)) +    (define-syntax-rules and () +      ((and) '#t) +      ((and x) x) +      ((and x . xs) (if x (and . xs) #f))) +    (define-core-function not (x) not) +    (define-core-function equal? (x y) equal?) +    (current-system))) + +(define-syntax define-system +  (syntax-rules () +    ((_ name (systems ...) expr ...) +     (define* (name #:optional (parent (core-system))) +       (when (member 'name (list 'systems ...)) +         (raise-exception +          (make-exception +           (make-exception-with-origin 'name) +           (make-exception-with-message "recursive system") +           (make-exception-with-irritants '(systems ...))))) +       (parameterize ((current-system +                       ((compose systems ... identity) parent))) +         expr +         ... +         (current-system)))))) + +(define (validate-function-name desc name) +  (define (err) +    (raise-exception +     (make-exception +      (make-exception-with-origin 'desc) +      (make-exception-with-message "unbound function") +      (make-exception-with-irritants name)))) +  (cond +   ((lookup name (current-system)) +    => (lambda (f) +         (if (is-a? f <function*>) +             name +             (err)))) +   (else (err)))) + +(define-syntax set-measure-predicate +  (syntax-rules () +    ((_ name) +     (begin +       (validate-function-name 'set-measure-predicate 'name) +       (current-system (update-measure-predicate 'name (current-system))))))) + +(define-syntax set-measure-less-than +  (syntax-rules () +    ((_ name) +     (begin +       (validate-function-name 'set-measure-less-than 'name) +       (current-system +        (update-measure-less-than 'name (current-system))))))) + +(define (defined-function-app-form f) +  (app-form (get-name f) (get-variables f))) + +(define (single? x) +  (and (pair? x) +       (null? (cdr x)))) + +(define (smart-if x y z) +  (cond +   ((equal? y z) y) +   ((equal? x ''#t) y) +   ((equal? x ''#f) z) +   (else `(if ,x ,y ,z)))) + +(define (smart-and . args) +  (cond +   ((null? args) ''#t) +   ((equal? ''#t (car args)) (apply smart-and (cdr args))) +   (else +    (let ((rest (apply smart-and (cdr args)))) +      (if (equal? ''#t rest) +          (car args) +          (smart-if (car args) +                    rest +                    ''#f)))))) + +(define (smart-implies x y) +  (cond +   ((equal? ''#f x) ''#t) +   ((equal? ''#t y) ''#t) +   (else +    (smart-if x y ''#t)))) + +(define (make-totality-claim* sys m-expr f) +  (let* ((name (get-name f))) +    (define (convert app-form) +      (cond +       ((apply-rule '() +                    (rule (get-variables f) +                          '() +                          (defined-function-app-form f) +                          m-expr) +                    app-form +                    '()) +        => identity) +       (else (error "make-totality-claim: convert error" +                    (get-name f) +                    m-expr +                    app-form)))) +    (smart-if `(,(get-measure-predicate sys) ,m-expr) +              (let loop ((expr (get-expression f))) +                (cond +                 ((expr-quoted? expr) ''#t) +                 ((variable? expr) ''#t) +                 ((if-form? expr) +                  (let ((test/result (loop (if-form-test expr))) +                        (then/result (loop (if-form-then expr))) +                        (else/result (loop (if-form-else expr)))) +                    (smart-and test/result +                               (smart-if (if-form-test expr) +                                         then/result +                                         else/result)))) +                 ((app-form? expr) +                  (let ((rest +                         (let f ((args (app-form-args expr))) +                           (cond ((null? args) ''#t) +                                 ((single? args) (loop (car args))) +                                 (else (smart-and (loop (car args)) +                                                  (f (cdr args)))))))) +                    (if (eq? name (app-form-name expr)) +                        (smart-and `(,(get-measure-less-than sys) +                                     ,(convert expr) +                                     ,m-expr) +                                   rest) +                        rest))) +                 (else (error "(vikalpa) make-totality-claim: error" +                              (get-name f) +                              m-expr)))) +              ''#f))) + +(define (make-guard-claim expr sys) +  (define (find-preconds expr) +    (cond +     ((app-form? expr) +      (let ((rest (append-map find-preconds (cdr expr)))) +        (append (cond ((lookup (car expr) sys) => +                       (lambda (f) +                         (let ((preconds (get-guards f))) +                           (map (lambda (precond) +                                  (substitute (map cons +                                                   (get-variables f) +                                                   (cdr expr)) +                                              precond)) +                                preconds)))) +                      (else (error "make-guard-claim: error" (car expr)))) +                rest))) +     ((if-form? expr) +      (find-preconds (if-form-test expr))) +     (else '()))) +  (define (build/find-if expr) +    (cond +     ((if-form? expr) +      (smart-if (build/find-if (if-form-test expr)) +                (build (if-form-then expr)) +                (build (if-form-else expr)))) +     ((app-form? expr) +      (apply smart-and (map build/find-if (app-form-args expr)))) +     (else ''#t))) +  (define (build expr) +    (cond +     ((if-form? expr) +      (apply smart-and +             (append (find-preconds (if-form-test expr)) +                     (list (smart-if (if-form-test expr) +                                     (build (if-form-then expr)) +                                     (build (if-form-else expr))))))) +     ((app-form? expr) +      (apply smart-and +             (append (find-preconds expr) +                     (list (build/find-if expr))))) +     (else ''#t))) +  (build expr)) + +(define (make-induction-claim f vars c) +  (unless (is-a? f <expandable-function>) +    (raise-exception +     (make-exception +      (make-exception-with-origin 'define-proof) +      (make-exception-with-message +       "measure function must be expandable function") +      (make-exception-with-irritants (get-name f))))) +  (define (find-app-forms expr) +    (cond +     ((app-form? expr) +      (let ((rest (append-map find-app-forms (cdr expr)))) +        (if (eq? (get-name f) (app-form-name expr)) +            (cons expr rest) +            rest))) +     ((if-form? expr) +      (error "make-induction-claim(find-app-forms): not supported" +             expr)) +     (else '()))) +  (define (prop form) +    (cond +     ((apply-rule '() +                  (rule vars +                        '() +                        (app-form (get-name f) vars) +                        c) +                  form +                  '()) +      => identity) +     (else +      (error "make-induction-claim: fail" app-form)))) +  (cond +   ((apply-function f vars) +    => (lambda (expr) +         (let build ((expr expr)) +           (cond +            ((if-form? expr) +             (let ((app-forms (find-app-forms (if-form-test expr)))) +               (smart-implies (if (null? app-forms) +                                  ''#t +                                  (fold smart-implies +                                        c +                                        (map prop app-forms))) +                              (smart-if (if-form-test expr) +                                        (build (if-form-then expr)) +                                        (build (if-form-else expr)))))) +            (else +             (let ((app-forms (find-app-forms expr))) +               (fold smart-implies c (map prop app-forms)))))))) +   (else (error "make-induction-claim: invalid" +                f vars c)))) + +(define (validate-sequence sys d seq) +  (for-each (lambda (r) +              (match r +                (('rewrite _ _ . command-ops) +                 (for-each (lambda (x) +                             (match x +                               (('set var expr) +                                (validate-expression sys +                                                     `(define-proof ,(get-name d)) +                                                     (get-variables d) +                                                     expr)) +                               (else #f))) +                           command-ops)) +                (else #f))) +            seq)) + +(define (add-proof/function sys f seed seq) +  (define (update-claim claim) +    (update-definition (make <total-function> +                         #:name (get-name f) +                         #:variables (get-variables f) +                         #:guards (get-guards f) +                         #:expression (get-expression f) +                         #:code (get-code f) +                         #:claim claim +                         #:proof seq) +                       sys)) +  (validate-sequence sys f seq) +  (if seed +      (begin +        (validate-expression sys +                             `(defien-proof ,(get-name f)) +                             (get-variables f) +                             seed) +        (update-claim +         (fold smart-implies +               (make-totality-claim* sys seed f) +               (get-guards f)))) +      (raise-exception +       (make-exception +        (make-exception-with-origin 'define-proof) +        (make-exception-with-message "need measure expression") +        (make-exception-with-irritants (get-expression f)))))) + +(define (add-proof/theorem sys t seed seq) +  (define (seed-error m) +    (raise-exception +     (make-exception +      (make-exception-with-origin 'define-proof) +      (make-exception-with-message (string-append "invalid seed: " m)) +      (make-exception-with-irritants (list (get-name t) seed))))) +  (validate-sequence sys t seq) +  (let ((claim +         (if seed +             (match seed +               ((fname vars ...) +                (cond +                 ((lookup fname sys) +                  => (cut make-induction-claim <> vars (get-expression t))) +                 (else (seed-error "function not found")))) +               (else (seed-error "format error"))) +             (get-expression t)))) +    (update-definition (make <theorem> +                         #:name (get-name t) +                         #:variables (get-variables t) +                         #:expression (get-expression t) +                         #:claim claim +                         #:proof seq) +                       sys))) + +(define (add-proof sys name seed seq) +  (cond +   ((not (sequence? seq)) +    (raise-exception +     (make-exception +      (make-exception-with-origin 'define-proof) +      (make-exception-with-message "not sequence") +      (make-exception-with-irritants seq)))) +   ((lookup name sys) +    => (lambda (def) +         (current-system +          (if (and (is-a? def <provable>) +                   (not (is-a? def <proved>))) +              (cond +               ((is-a? def <function>) +                (add-proof/function sys def seed seq)) +               ((is-a? def <conjecture>) +                (add-proof/theorem sys def seed seq)) +               (else +                (raise-exception +                 (make-exception +                  (make-exception-with-origin 'define-proof) +                  (make-exception-with-message "error") +                  (make-exception-with-irritants def))))) +              (raise-exception +               (make-exception +                (make-exception-with-origin 'define-proof) +                (make-exception-with-message "not provable definition") +                (make-exception-with-irritants def))))))) +   (else +    (raise-exception +     (make-exception +      (make-exception-with-origin 'define-proof) +      (make-exception-with-message "definition is not found") +      (make-exception-with-irritants name)))))) + +(define-syntax define-proof +  (syntax-rules () +    ((_ name +        seed +        seq) +     (add-proof (current-system) +                'name +                'seed +                'seq)) +    ((_ name seq) +     (define-proof name #f seq)))) + +(define (validate-expression/error sys name vars expr) +  (with-exception-handler +      (lambda (e) +        (if (eq? 'validate-expression/error (exception-origin e)) +            `(error ,name ,vars ,expr)) +        (raise-exception e)) +    (lambda () +      (validate-expression sys 'validate-expression/error vars expr) +      #f))) + +(define (validate-expression sys name vars expr) +  (let* ((expr-fnames (expression-functions expr)) +         (expr-vars (expression-vars expr)) +         (expr-app-forms (expression-app-forms expr))) +    (define (err msg x) +      (raise-exception +       (make-exception +        (make-exception-with-origin name) +        (make-exception-with-message msg) +        (make-exception-with-irritants x)))) +    (for-each (lambda (x) +                (when (member x expr-fnames) +                  (err "invalid variable" x))) +              vars) +    (for-each (lambda (fname) +                (unless (cond +                         ((lookup fname sys) => +                          (lambda (f) +                            (for-each +                             (lambda (app-form) +                               (when (equal? fname (app-form-name app-form)) +                                 (unless (= (length (get-variables f)) +                                            (length (app-form-args app-form))) +                                   (err (format +                                         #f +                                         "~a :wrong number of arguments ~s" +                                         (get-name f) +                                         (get-variables f)) +                                        (app-form-args app-form))))) +                             expr-app-forms) +                            #t)) +                         (else #f)) +                  (err "undefined function" fname))) +              expr-fnames) +    (for-each (lambda (x) +                (unless (member x vars) +                  (err "undefined variable" x))) +              expr-vars))) + +(define (dup? xs) +  (if (null? xs) +      #f +      (if (member (car xs) (cdr xs)) +          #t +          (dup? (cdr xs))))) + +(define (validate-vars desc vars) +  (define (err) +    (raise-exception +     (make-exception +      (make-exception-with-message +       (string-append "(vikalpa) " desc ": duplicated variable")) +      (make-exception-with-irritants vars)))) +  (when (dup? vars) +    (err))) + +(define-method (get-type (s <axiom>)) 'axiom) +(define-method (get-type (s <theorem>)) 'theorem) +(define-method (get-type (s <conjecture>)) 'conjecture) +(define-method (get-type (s <core-function>)) 'core-function) +(define-method (get-type (s <function>)) 'function) +(define-method (get-type (s <total-function>)) 'total-function) +(define-method (get-type (s <admitted-function>)) 'admitted-function) +(define-method (get-type (s <admitted-theorem>)) 'admitted-theorem) +(define-method (get-type (s <macro>)) 'macro) + +(define-method (show (d <macro>)) +  (list (get-type d))) +(define-method (show (d <theorem*>)) +  (list (get-type d) +        (get-variables d) +        (get-expression d))) +(define-method (show (d <core-function>)) +  (list (get-type d) +        (get-variables d))) +(define-method (show (d <expandable-function>)) +  (list (get-type d) +        (get-variables d) +        (get-expression d))) +(define-method (show (d <admitted-function>)) +  (list (get-type d) +        (get-variables d) +        (get-expression d))) + +(define* (system-apropos sys str) +  (filter-map (lambda (d) +                (let ((name (format #f "~a" (get-name d)))) +                  (if (string-match (string-append ".*" +                                                   (regexp-quote str) +                                                   ".*") +                                    name) +                      (list (get-name d) (show d)) +                      #f))) +              (get-definitions sys))) + +(define (system-check/guard sys) +  (filter-map (lambda (f) +                (if (lookup `(guard ,(get-name f)) sys) +                    #f +                    (if (equal? (make-guard-claim (get-expression f) sys) +                                ''#t) +                        #f +                        `((guard ,(get-name f)) +                          (add (define-guard-theorem ,(get-name f))))))) +              (filter (cut is-a? <> <expandable-function>) +                      (get-definitions sys)))) + +(define (system-check sys) +  (append +   (system-check/guard sys) +   (let loop ((sys sys) +              (fails '())) +     (if (system-empty? sys) +         fails +         (let ((d (first-definition sys)) +               (sys-without-first (remove-first-definition sys))) +           (define* (next #:optional fail) +             (loop sys-without-first +                   (if fail +                       (cons fail fails) +                       fails))) +           (cond +            ((is-a? d <proved>) +             (let ((result +                    (if (is-a? d <theorem>) +                        (rewrite sys-without-first +                                 (get-claim d) +                                 (get-proof d)) +                        (rewrite sys +                                 (get-claim d) +                                 (get-proof d))))) +               (cond +                ((equal? result (result/expr ''#t)) +                 (next)) +                (else +                 (next (list (get-name d) result)))))) +            ((is-a? d <provable>) +             (next (list (get-name d)))) +            (else (next)))))))) + +(define (system? x) +  (is-a? x <system>)) + +(define/guard (system-lookup (sys system?) (name (const #t))) +  (cond +   ((lookup name sys) => show) +   (else #f))) + +(define/guard (system-rewrite (sys system?) (expr (const #t)) (seq sequence?)) +  (rewrite sys (convert-to-expression expr) seq)) | 
