summaryrefslogtreecommitdiff
path: root/vikalpa.scm
diff options
context:
space:
mode:
authorMasaya Tojo <masaya@tojo.tokyo>2020-11-09 02:56:59 +0900
committerMasaya Tojo <masaya@tojo.tokyo>2020-11-09 02:56:59 +0900
commit7a238e7df0c9c7c684b7f761f495b21aa088bd68 (patch)
tree299eb84b8706557655a6ea01d32ab37ec94d2789 /vikalpa.scm
parent51b6399599676a5c1a9c6cb27be88a1381f7af8a (diff)
wip10
Diffstat (limited to 'vikalpa.scm')
-rw-r--r--vikalpa.scm743
1 files changed, 743 insertions, 0 deletions
diff --git a/vikalpa.scm b/vikalpa.scm
new file mode 100644
index 0000000..5a51cfa
--- /dev/null
+++ b/vikalpa.scm
@@ -0,0 +1,743 @@
+;;; Vikalpa --- Prove S-expression
+;;; Copyright © 2020 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 (rewrite)
+ #:use-module (vikalpa syntax)
+ #:use-module (vikalpa primitive)
+ #:use-module (ice-9 match)
+ #:use-module ((srfi srfi-1) #:select (every any member))
+ #:use-module (srfi srfi-8)
+ #:use-module (srfi srfi-26))
+
+(define (option p?)
+ (lambda (x)
+ (or (p? x) (not x))))
+
+(define (list-of p?)
+ (lambda (x)
+ (and (list? x)
+ (every p? x))))
+
+;; (expression? x) -> boolean?
+(define (expression? expr)
+ (cond ((expr-quoted? expr)
+ (or (integer? (expr-unquote expr))
+ (boolean? (expr-unquote expr))
+ (symbol? (expr-unquote expr))))
+ ((pair? expr)
+ (and (expression? (car expr))
+ (list? (cdr expr))
+ (every expression? (cdr expr))))
+ ((variable? expr) #t)
+ (else #f)))
+
+(define (all-vars x)
+ (cond ((expr-quoted? x) '())
+ ((pair? x)
+ (append (all-vars (car x))
+ (all-vars (cdr x))))
+ ((variable? x) (list x))
+ (else '())))
+
+;; (expr-quoted? x) -> boolean?
+(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)))
+
+;; (expr-quoted? x) -> boolean?
+(define (expr-quote expr)
+ (list 'quote expr))
+
+;; (variable? x) -> boolean?
+(define (variable? x)
+ (symbol? x))
+
+;; (variable=? variable? variable?) -> boolean?
+(define (variable=? v1 v2)
+ (eq? v1 v2))
+
+;; (rule? x) -> boolean?
+(define (rule? x)
+ (and (list? x)
+ (= 5 (length x))
+ (eq? (car x) 'rule)
+ (let ((vars (list-ref x 1)))
+ (and (list? vars)
+ (every variable? vars)))
+ (let ((preconds (list-ref x 2)))
+ (and (list? preconds)
+ (every expression? preconds)))
+ (expression? (list-ref x 3))
+ (expression? (list-ref x 4))))
+
+;; (rule (list-of variable?) expression? expression?) -> rule?
+(define (rule vars preconds lhs rhs)
+ (list 'rule vars preconds lhs rhs))
+
+;; (rule-vars rule?) -> (list-of variable?)
+(define (rule-vars r)
+ (list-ref r 1))
+
+;; (rule-preconds rule?) -> expression?
+(define (rule-preconds r)
+ (list-ref r 2))
+
+;; (rule-lhs rule?) -> expression?
+(define (rule-lhs r)
+ (list-ref r 3))
+
+;; (rule-rhs rule?) -> expression?
+(define (rule-rhs r)
+ (list-ref r 4))
+
+;; (environment x) -> boolean?
+;; environment is alist
+(define (environment x)
+ (cond ((null? x) #t)
+ ((pair? x)
+ (and (pair? (car x))
+ (variable? (car (car x)))
+ (expression? (cdr (car x)))
+ (environment (cdr x))))
+ (else #f)))
+
+;; (apply-rule preconds rule? expression?) -> (or (cons rhs environment) #f)
+(define (apply-rule preconds rl expr)
+ (define (var? v)
+ (and (member v (rule-vars rl))
+ #t))
+ (call/cc
+ (lambda (k)
+ (define (mat-map lhss exprs env)
+ (cond ((and (pair? lhss)
+ (pair? exprs))
+ (mat-map (cdr lhss)
+ (cdr exprs)
+ (mat (car lhss)
+ (car exprs)
+ env)))
+ ((and (null? lhss)
+ (null? exprs))
+ env)
+ (else (k #f))))
+ (define (mat lhs expr env)
+ (cond ((expr-quoted? lhs)
+ (if (expr-quoted? expr)
+ (and (equal? lhs expr)
+ env)
+ (k #f)))
+ ((pair? lhs)
+ (if (and (pair? expr)
+ (symbol? (car lhs))
+ (eqv? (car lhs) (car expr)))
+ (mat-map (cdr lhs) (cdr 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))))
+ (else (k #f))))
+ (define (mat-preconds rlps env)
+ (if (null? rlps)
+ env
+ (mat-preconds (cdr rlps)
+ (any (lambda (p) (mat (car rlps) p env))
+ preconds))))
+ (define (substitute env expr)
+ (cond ((expr-quoted? expr) expr)
+ ((pair? expr)
+ (cons (substitute env (car expr))
+ (substitute env (cdr expr))))
+ ((and (variable? expr) (assoc expr env)) => cdr)
+ (else expr)))
+ (substitute (mat (rule-lhs rl)
+ expr
+ (mat-preconds (rule-preconds rl) '()))
+ (rule-rhs rl)))))
+
+;; (book? x) -> boolean?
+;; book is alist
+(define (book? x)
+ (cond ((null? x) #t)
+ ((pair? x)
+ (and (pair? (car x))
+ (or (proposition? (car x))
+ (primitive-function? (car x))
+ (macro? (car x))
+ (function? (car x)))
+ (book? (cdr x))))
+ (else #f)))
+
+(define (primitive-function? x)
+ (and (list? x)
+ (= 4 (length x))
+ (variable? (list-ref x 0))
+ (eq? 'primitive-function (list-ref x 1))
+ (let ((ps (list-ref x 2)))
+ (and (list? ps)
+ (every procedure? ps)))
+ (procedure? (list-ref x 3))))
+
+;; (primitive-function variable? (list-of procedure?) procedure?) -> primitive-function?
+(define (primitive-function name ps proc)
+ (list name 'primitive-function ps proc))
+
+(define (primitive-function-name pf)
+ (list-ref pf 0))
+
+(define (primitive-function-preds pf)
+ (list-ref pf 2))
+
+(define (primitive-function-proc pf)
+ (list-ref pf 3))
+
+(define (match-primitive-function pf expression)
+ (and (pair? expression)
+ (eq? (primitive-function-name pf) (car expression))
+ (list? (cdr expression))
+ (every identity (map (lambda (pred expr)
+ (and (expr-quoted? expr)
+ (pred (expr-unquote expr))))
+ (primitive-function-preds pf)
+ (cdr expression)))))
+
+(define (apply-primitive-function pf expression)
+ (apply (primitive-function-proc pf) (cdr expression)))
+
+(define (function? x)
+ (and (list? x)
+ (= 4 (length x))
+ (variable? (function-name x))
+ (eq? 'function (list-ref x 1))
+ (vars? (function-vars x))
+ (expression? (function-expression x))))
+
+;; (function variable? vars? expression?) -> function?
+(define/guard (function (name variable?) (vars vars?) (expr expression?))
+ (list name 'function vars expr))
+
+(define (function-name f)
+ (list-ref f 0))
+
+(define (function-vars f)
+ (list-ref f 2))
+
+(define (function-expression f)
+ (list-ref f 3))
+
+(define (mrule? x)
+ (and (list? x)
+ (= 4 (length x))
+ (eq? 'mrule (list-ref x 0))
+ (vars? (mrule-vars x))
+ ((const #t) (mrule-lhs x))
+ ((const #t) (mrule-rhs x))))
+
+(define (mrule vars lhs rhs)
+ (list 'mrule vars lhs rhs))
+
+(define (mrule-vars mrl)
+ (list-ref mrl 1))
+
+(define (mrule-lhs mrl)
+ (list-ref mrl 2))
+
+(define (mrule-rhs mrl)
+ (list-ref mrl 3))
+
+(define (macro? x)
+ (and (list? x)
+ (= 3 (length x))
+ (eq? 'macro (list-ref x 1))
+ (variable? (macro-name x))
+ (let ((mrls (macro-mrules x)))
+ (and (list? mrls)
+ (every mrule? mrls)))))
+
+(define (macro-name m)
+ (list-ref m 0))
+
+(define (macro-mrules m)
+ (list-ref m 2))
+
+(define (macro name rules)
+ (list name 'macro rules))
+
+(define (apply-mrule rl expr)
+ (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)
+ (and (equal? lhs expr)
+ env)
+ (k #f)))
+ ((and (pair? lhs)
+ (pair? expr))
+ (mat-map lhs expr env))
+ ((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 (substitute env expr)
+ (cond ((expr-quoted? expr) expr)
+ ((pair? expr)
+ (cons (substitute env (car expr))
+ (substitute env (cdr expr))))
+ ((and (variable? expr) (assoc expr env)) => cdr)
+ (else expr)))
+ (substitute (mat (mrule-lhs rl)
+ expr
+ '())
+ (mrule-rhs rl)))))
+
+(define (apply-macro m expr)
+ (cond ((and (pair? expr)
+ (eq? (macro-name m) (car expr)))
+ (let loop ((rs (macro-mrules m)))
+ (cond ((null? rs) expr)
+ ((apply-mrule (car rs) expr) => identity)
+ (else (loop (cdr rs))))))
+ (else #f)))
+
+(define/guard (expand (ms (list-of macro?)) (expr (const #t)))
+ (let loop ((ms ms)
+ (expr expr))
+ (cond
+ ((null? ms) expr)
+ (else (expand (cdr ms)
+ (cond
+ ((apply-macro (car ms) expr) => identity)
+ (else expr)))))))
+
+(define/guard (expand* (ms (list-of macro?)) (expr (const #t)))
+ (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)))))
+
+;; (axiom variable? vars? expression?) -> axiom?
+;; axiom? is proposition
+(define/guard (axiom (name variable?) (vars vars?) (expr expression?))
+ (list name 'axiom vars expr))
+
+(define (vars? x)
+ (and (list? x)
+ (every variable? x)))
+
+;; (axiom? x) -> boolean?
+(define (axiom? x)
+ (and (list? x)
+ (= 4 (length x))
+ (variable? (list-ref x 0))
+ (eq? 'axiom (list-ref x 1))
+ (vars? (list-ref x 2))
+ (expression? (list-ref x 3))))
+
+;; (theorem name vars? expression?) -> theorem?
+(define/guard (theorem (name variable?) (vars vars?) (expr expression?))
+ (list name 'theorem vars expr))
+
+;; (theorem? x) -> boolean?
+;; theorem? is proposition
+(define (theorem? x)
+ (and (list? x)
+ (= 4 (length x))
+ (variable? (list-ref x 0))
+ (eq? 'theorem (list-ref x 1))
+ (vars? (list-ref x 2))
+ (expression? (list-ref x 3))))
+
+(define (theorem-name x)
+ (list-ref x 0))
+
+;; (proposition? x) -> boolean?
+(define (proposition? x)
+ (or (axiom? x)
+ (theorem? x)))
+
+(define (proposition-name x)
+ (list-ref x 0))
+
+(define (proposition-vars x)
+ (list-ref x 2))
+
+(define (proposition-expression x)
+ (list-ref x 3))
+
+(define (proposition-rules x)
+ (expression->rules (proposition-vars x)
+ '()
+ (proposition-expression x)))
+
+;; (rewriter path? command?) -> rewriter?
+(define (rewriter p c)
+ (list p c))
+
+(define (rewriter-path r)
+ (list-ref r 0))
+
+(define (rewriter-command r)
+ (list-ref r 1))
+
+(define (rewriter? x)
+ (and (pair? x)
+ (path? (car x))
+ (pair? (cdr x))
+ (command? (car (cdr x)))
+ (null? (cdr (cdr x)))))
+
+;; (sequence? x) -> boolean?
+(define (sequence? x)
+ (and (list? x)
+ (every rewriter? x)))
+
+;; (path? x) -> boolean?
+;; path is list
+(define (path? x)
+ (and (list? x)
+ (every natural? x)))
+
+;; (command? x) -> booelan?
+(define (command? x)
+ (or (symbol? x)
+ ((list-of symbol?) x)))
+
+;; (extract path? expression? preconds? procedure?) -> (values expression? procedure?)
+(define (extract path expr fail)
+ (if (null? path)
+ (values expr '() identity)
+ (let ((i (car path)))
+ (cond
+ ((expr-if? expr)
+ (let ((precond (expr-if-cond expr)))
+ (receive (extracted-expr extracted-preconds builder)
+ (extract (cdr path) (list-ref expr i) fail)
+ (values extracted-expr
+ (case i
+ ((1) '())
+ ((2) (cons precond extracted-preconds))
+ ((3) (cons (expr-not precond) extracted-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 (function-vars x)
+ '()
+ (cons (function-name x)
+ (function-vars x))
+ (function-expression x))
+ (rule (function-vars x)
+ '()
+ (function-expression x)
+ (cons (function-name x)
+ (function-vars x)))))
+
+;; (rewrite book? rewriter? expression? procedure?) -> expr
+(define (rewrite1 b expr fail r)
+ (let ((cmd (rewriter-command r)))
+ (receive (extracted-expr preconds builder)
+ (extract (rewriter-path r) expr fail)
+ (builder
+ (cond
+ ((equal? cmd '(expand))
+ (expand (filter macro? b) extracted-expr))
+ ((equal? cmd '(expand*))
+ (expand* (filter macro? b) extracted-expr))
+ ((and (symbol? cmd)
+ (assoc cmd b))
+ => (lambda (x)
+ (cond
+ ((proposition? x)
+ (cond
+ ((any (cut apply-rule preconds <> extracted-expr)
+ (proposition-rules x)) => identity)
+ (else
+ (fail (format #f "no match-rule (~a)" cmd)))))
+ ((function? x)
+ (cond
+ ((any (cut apply-rule '() <> extracted-expr)
+ (function->rules x)) => identity)
+ (else
+ (fail (format #f "no match-rule (~a)" cmd)))))
+ ((primitive-function? x)
+ (cond
+ ((match-primitive-function x extracted-expr)
+ (apply-primitive-function x extracted-expr))
+ (else
+ (fail "can't apply-primitive-function (~a)" cmd))))
+ ((macro? x)
+ (cond
+ ((apply-macro x extracted-expr) => identity)
+ (else
+ (fail "macro fail"))))
+ (else
+ (fail "rewrite error")))))
+ (else (fail "no cmd (~a)" cmd)))))))
+
+(define/guard (rewrite (b book?) (expr expression?) (seq sequence?))
+ (let loop ((expr expr)
+ (seq seq))
+ (if (null? seq)
+ expr
+ (loop (rewrite1 b
+ expr
+ (lambda (x . args)
+ (apply error
+ (format #f "rewrite: ~a" x)
+ args))
+ (car seq))
+ (cdr seq)))))
+
+(define (expr-not x)
+ (list 'not x))
+
+(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 (expr-if? x)
+ (and (list? x)
+ (= 4 (length x))
+ (eq? 'if (list-ref x 0))
+ (expression? (list-ref x 1))
+ (expression? (list-ref x 2))
+ (expression? (list-ref x 3))))
+
+(define (expr-if-cond x)
+ (list-ref x 1))
+
+(define (expr-if-then x)
+ (list-ref x 2))
+
+(define (expr-if-else x)
+ (list-ref x 3))
+
+(define (expression->rules vars preconds expr)
+ (if (expr-if? expr)
+ (append (expression->rules vars
+ (cons (expr-if-cond expr) preconds)
+ (expr-if-then expr))
+ (expression->rules vars
+ (cons (expr-not (expr-if-cond expr)) preconds)
+ (expr-if-else 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 (proposition->rules def)
+ (expression->rules (proposition-vars def)
+ '()
+ (proposition-expression def)))
+
+(define current-book (make-parameter '()))
+
+(define (add-book x)
+ (let ((b (current-book)))
+ (current-book
+ (cond ((assoc (proposition-name x) b)
+ => (lambda (prop)
+ (if (equal? x prop)
+ b
+ (error "add-book: error"))))
+ (else (cons x b))))))
+
+(define-syntax define-axiom
+ (syntax-rules ()
+ ((_ name (var ...) expr)
+ (add-book (axiom 'name '(var ...) 'expr)))))
+
+(define-syntax define-theorem
+ (syntax-rules ()
+ ((_ name (var ...) expr)
+ (add-book (theorem 'name '(var ...) 'expr)))))
+
+(define-syntax define-function
+ (syntax-rules ()
+ ((_ name (var ...) expr)
+ (let ((f (function 'name '(var ...) 'expr)))
+ (add-book f)
+ f))))
+
+(define-syntax define-macro
+ (syntax-rules ()
+ ((_ name () ((lhs1 . lhs2) rhs) ...)
+ (add-book (macro 'name
+ (list (mrule (all-vars 'lhs2) '(lhs1 . lhs2) 'rhs)
+ ...))))))
+
+(define-syntax define-book
+ (syntax-rules ()
+ ((_ name (books ...) expr ...)
+ (define* (name #:optional (parent '()))
+ (parameterize ([current-book ((compose books ... identity) parent)])
+ expr
+ ...
+ (unless (book? (current-book))
+ (error "define-book: error"))
+ (current-book))))))
+
+(define-book prelude ()
+ (define-axiom equal-same (x)
+ (equal? (equal? x x) '#t))
+ (define-axiom equal-swap (x y)
+ (equal? (equal? x y) (equal? y x)))
+ (define-axiom equal-if (x y)
+ (if (equal? x y) (equal? x y) '#t))
+ (define-axiom pair/cons (x y)
+ (equal? (pair? (cons x y)) '#t))
+ (define-axiom car/cons (x y)
+ (equal? (car (cons x y)) x))
+ (define-axiom cdr/cons (x y)
+ (equal? (cdr (cons x y)) y))
+ (define-axiom cons/car+cdr (x y)
+ (equal? (if (pair? x)
+ (equal? (cons (car x) (cdr y)) x)
+ '#t)
+ y))
+ (define-axiom cons/car+cdr (x y)
+ (equal? (if (pair? x)
+ (equal? (cons (car x) (cdr y)) x)
+ '#t)
+ y))
+ (define-axiom if-same (x y)
+ (equal? (if x y y) y))
+ (define-axiom size/car (x)
+ (if (pair? x)
+ (equal? (< (size x) (size (car x)))
+ '#t)
+ '#t))
+ (define-axiom size/cdr (x)
+ (if (pair? x)
+ (equal? (< (size x) (size (cdr x)))
+ '#t)
+ '#t))
+ (define-macro list ()
+ ((list) '())
+ ((list x . y) (cons x (list . y))))
+ (define-macro + ()
+ ((+) '0)
+ ((+ x) x)
+ ((+ x . xs) (b+ x (+ . xs))))
+ (define-macro - ()
+ ((- x) (u- x))
+ ((- x . xs) (+ x . (u- (+ . xs)))))
+ (define-macro and ()
+ ((and) '#t)
+ ((and x) x)
+ ((and x . xs) (if x (and . xs) #f)))
+ (define-macro or ()
+ ((or) '#f)
+ ((or x) x)
+ ((or x . xs) (if x x (or . xs))))
+ (define-macro atom? ()
+ ((atom? x) (not (pair? x))))
+ (define-axiom if-not (x y z)
+ (equal? (if (not x)
+ y
+ z)
+ (if x
+ z
+ y))))
+
+(define-book app (prelude)
+ (define-function app (x y)
+ (if (atom? x)
+ y
+ (cons x (app x y))))
+
+ (define-theorem associate-app (x y z)
+ (equal? (app (app x y) z)
+ (app x (app y z)))))
+
+(define (size x)
+ (if (pair? x)
+ (+ 1
+ (size (car x))
+ (size (cdr x)))
+ 0))