EoPL reading (98) 2.2 An Abstraction for Inductive Data Type
beta-reduction の検討着手。
beta 簡約については op が lambda な手続き呼び出しに限定してみる。プロトタイプとしては以下なカンジ?
(define beta-reduction (lambda (exp) (cases expression exp (app-exp (rator rand) (cases expression rator (lambda-exp (id body) (substitute id body rand)) (else exp))) (else (eopl:error 'alpha-conversion "invalid expression ~s" exp)))))
substitute は以下なカンジ。最初のバージョンと異なるのは lambda なケイスのみ。
(define substitute (lambda (sym list exp) (cases expression list (lit-exp (datum) (lit-exp datum)) (var-exp (id) (if (eqv? sym id) exp (var-exp id))) (lambda-exp (id body) (lambda-exp id body)) (primapp-exp (prim rand1 rand2) (primapp-exp prim (substitute sym rand1 exp) (substitute sym rand2 exp))) (app-exp (rator rand) (cases expression rator (lambda-exp (id body) (app-exp rator (substitute sym rand exp))) (else (app-exp (substitute sym rator exp) (substitute sym rand exp))))))))
試験を考えてみる事に。まず subst な手続きから着手して以下な試験にパス。
(use gauche.test) (add-load-path ".") (load "beta-reduction") (test-start "beta-reduction") (test-section "substitute") (test* "(subst 'x '(lit-exp 1) (lit-exp 2))" '(lit-exp 1) (substitute 'x '(lit-exp 1) '(lit-exp 2))) (test* "(subst 'x '(var-exp x) (lit-exp 2))" '(lit-exp 2) (substitute 'x '(var-exp x) '(lit-exp 2))) (test* "(subst 'y '(var-exp x) (lit-exp 2))" '(var-exp x) (substitute 'y '(var-exp x) '(lit-exp 2))) (test-end)
で、次は lambda なんですが
((lambda (x) (lambda (x) x)) 2)
みたいな式を beta 簡約って微妙。ケイス的に以下?
((lambda (x) (lambda (x) x)) 2) ;; (lambda (x) x) を戻す ((lambda (x) (lambda (x) y)) 2) ;; (lambda (x) y) を戻す ((lambda (x) (lambda (y) x)) 2) ;; (lambda (y) 2) を戻す ((lambda (x) (lambda (y) y)) 2) ;; (lambda (y) y) を戻す
むーん。これって x に occurs free なのは 3 番目って理解で OK かなぁ。試験で確認。
(test-section "beta-reduction") (test* "(occurs-free? 'x '(lambda (x) x))" #f (occurs-free? 'x '(lambda-exp x (var-exp x)))) (test* "(occurs-free? 'x '(lambda (x) y))" #f (occurs-free? 'x '(lambda-exp x (var-exp y)))) (test* "(occurs-free? 'x '(lambda (y) x))" #t (occurs-free? 'x '(lambda-exp y (var-exp x)))) (test* "(occurs-free? 'x '(lambda (y) y))" #f (occurs-free? 'x '(lambda-exp y (var-exp y))))
で、実行。
<beta-reduction>--------------------------------------------------------------- test (occurs-free? 'x '(lambda (x) x)), expects #f ==> ok test (occurs-free? 'x '(lambda (x) y)), expects #f ==> ok test (occurs-free? 'x '(lambda (y) x)), expects #t ==> ok test (occurs-free? 'x '(lambda (y) y)), expects #f ==> ok
当たり。lambda の場合はこうか。
(lambda-exp (id body) (lambda-exp id (if (occurs-free? sym list) (substitute sym body exp) body)))
てーコトはあとは試験を書いて確認すれば良いカンジでしょうか。まだまだ先は長いな。とりあえずざっくりベースで以下?
(test* "(subst 'x '(+ x 2) 3)" '(primapp-exp + (lit-exp 3) (lit-exp 2)) (substitute 'x '(primapp-exp + (var-exp x) (lit-exp 2)) '(lit-exp 3))) (test* "(subst 'x '(+ y 2) 3)" '(primapp-exp + (var-exp y) (lit-exp 2)) (substitute 'x '(primapp-exp + (var-exp y) (lit-exp 2)) '(lit-exp 3))) (test* "(subst 'x '(a x) 2)" '(app-exp (var-exp a) (lit-exp 2)) (substitute 'x '(app-exp (var-exp a) (var-exp x)) '(lit-exp 2))) (test* "(subst 'x '((lambda (x) x) 2) 3)" '(app-exp (lambda-exp x (var-exp x)) (lit-exp 2)) (substitute 'x '(app-exp (lambda-exp x (var-exp x)) '(lit-exp 2)) '(lit-exp 3))) (test* "(subst 'x '((lambda (y) y) x) 3)" '(app-exp (lambda-exp y (var-exp y)) (lit-exp 3)) (substitute 'x '(app-exp (lambda-exp y (var-exp y)) '(var-exp x)) (lit-exp 3))) (test* "(subst 'x '(x y) 'z)" '(app-exp (var-exp z) (var-exp y)) (substitute 'x '(app-exp (var-exp x) (var-exp y)) '(var-exp z)))
実装の変更は不要で試験パス。
Testing beta-reduction ======================================================== <substitute>------------------------------------------------------------------- test (subst 'x '(lit-exp 1) (lit-exp 2)), expects (lit-exp 1) ==> ok test (subst 'x '(var-exp x) (lit-exp 2)), expects (lit-exp 2) ==> ok test (subst 'y '(var-exp x) (lit-exp 2)), expects (var-exp x) ==> ok test (subst 'x '(lambda-exp x (var-exp x)) '(lit-exp 2)), expects (lambda-exp x (var-exp x)) ==> ok test (subst 'x '(lambda-exp x (var-exp y)) '(lit-exp 2)), expects (lambda-exp x (var-exp y)) ==> ok test (subst 'x '(lambda-exp y (var-exp x)) '(lit-exp 2)), expects (lambda-exp y (lit-exp 2)) ==> ok test (subst 'x '(lambda-exp y (var-exp y)) '(lit-exp 2)), expects (lambda-exp y (var-exp y)) ==> ok test (subst 'x '(+ x 2) 3), expects (primapp-exp + (lit-exp 3) (lit-exp 2)) ==> ok test (subst 'x '(+ y 2) 3), expects (primapp-exp + (var-exp y) (lit-exp 2)) ==> ok test (subst 'x '(a x) 2), expects (app-exp (var-exp a) (lit-exp 2)) ==> ok test (subst 'x '((lambda (x) x) 2) 3), expects (app-exp (lambda-exp x (var-exp x)) (lit-exp 2)) ==> ok test (subst 'x '((lambda (y) y) x) 3), expects (app-exp (lambda-exp y (var-exp y)) (lit-exp 3)) ==> ok test (subst 'x '(x y) 'z), expects (app-exp (var-exp z) (var-exp y)) ==> ok passed.
subst な手続きは OK と見て、beta-reduction 手続きの試験を検討。一応全部パス。試験を以下に。
(use gauche.test) (add-load-path ".") (load "beta-reduction") (test-start "beta-reduction") (test-section "error") (test* "lit-exp" *test-error* (beta-reduction '(lit-exp 1))) (test* "var-exp" *test-error* (beta-reduction '(var-exp x))) (test* "lambda-exp" *test-error* (beta-reduction '(lambda-exp x (var-exp x)))) (test* "primapp-exp" *test-error* (beta-reduction '(primapp-exp + (lit-exp 1) (lit-exp 2)))) (test-section "beta-reduction") (test* "(beta (x 2)" '(app-exp (var-exp x) (lit-exp 2)) (beta-reduction '(app-exp (var-exp x) (lit-exp 2)))) (test* "(beta ((lambda (x) 1) x))" '(lit-exp 1) (beta-reduction '(app-exp (lambda-exp x (lit-exp 1)) (var-exp x)))) (test* "(beta ((lambda (x) x) 1))" '(lit-exp 1) (beta-reduction '(app-exp (lambda-exp x (var-exp x)) (lit-exp 1)))) (test* "(beta ((lambda (x) (lambda (x) x)) 1))" '(lambda-exp x (var-exp x)) (beta-reduction '(app-exp (lambda-exp x (lambda-exp x (var-exp x))) (lit-exp 1)))) (test* "(beta ((lambda (x) (lambda (x) y)) 1))" '(lambda-exp x (var-exp y)) (beta-reduction '(app-exp (lambda-exp x (lambda-exp x (var-exp y))) (lit-exp 1)))) (test* "(beta ((lambda (x) (lambda (y) x)) 1))" '(lambda-exp y (lit-exp 1)) (beta-reduction '(app-exp (lambda-exp x (lambda-exp y (var-exp x))) (lit-exp 1)))) (test* "(beta ((lambda (x) (lambda (y) y)) 1))" '(lambda-exp y (var-exp y)) (beta-reduction '(app-exp (lambda-exp x (lambda-exp y (var-exp y))) (lit-exp 1)))) (test* "(beta ((lambda (x) (+ x 1)) 1))" '(primapp-exp + (lit-exp 1) (lit-exp 1)) (beta-reduction '(app-exp (lambda-exp x (primapp-exp + (var-exp x) (lit-exp 1))) (lit-exp 1)))) (test* "(beta ((lambda (x) (+ y 1)) 1))" '(primapp-exp + (var-exp y) (lit-exp 1)) (beta-reduction '(app-exp (lambda-exp x (primapp-exp + (var-exp y) (lit-exp 1))) (lit-exp 1)))) (test* "(beta ((lambda (x) (w x)) 1))" '(app-exp (var-exp w) (lit-exp 1)) (beta-reduction '(app-exp (lambda-exp x (app-exp (var-exp w) (var-exp x))) (lit-exp 1)))) (test* "(beta ((lambda (x) ((lambda (x) x) 2)) 3))" '(app-exp (lambda-exp x (var-exp x)) (lit-exp 2)) (beta-reduction '(app-exp (lambda-exp x (app-exp (lambda-exp x (var-exp x)) (lit-exp 2))) (lit-exp 3)))) (test* "(beta ((lambda (x) ((lambda (y) y) x)) 3))" '(app-exp (lambda-exp y (var-exp y)) (lit-exp 3)) (beta-reduction '(app-exp (lambda-exp x (app-exp (lambda-exp y (var-exp y)) (var-exp x))) (lit-exp 3)))) (test* "(beta ((lambda (x) (x y)) z))" '(app-exp (var-exp z) (var-exp y)) (beta-reduction '(app-exp (lambda-exp x (app-exp (var-exp x) (var-exp y))) (var-exp z)))) (test-section "substitute") (test* "(subst 'x '(lit-exp 1) (lit-exp 2))" '(lit-exp 1) (substitute 'x '(lit-exp 1) '(lit-exp 2))) (test* "(subst 'x '(var-exp x) (lit-exp 2))" '(lit-exp 2) (substitute 'x '(var-exp x) '(lit-exp 2))) (test* "(subst 'y '(var-exp x) (lit-exp 2))" '(var-exp x) (substitute 'y '(var-exp x) '(lit-exp 2))) (test* "(subst 'x '(lambda-exp x (var-exp x)) '(lit-exp 2))" '(lambda-exp x (var-exp x)) (substitute 'x '(lambda-exp x (var-exp x)) '(lit-exp 2))) (test* "(subst 'x '(lambda-exp x (var-exp y)) '(lit-exp 2))" '(lambda-exp x (var-exp y)) (substitute 'x '(lambda-exp x (var-exp y)) '(lit-exp 2))) (test* "(subst 'x '(lambda-exp y (var-exp x)) '(lit-exp 2))" '(lambda-exp y (lit-exp 2)) (substitute 'x '(lambda-exp y (var-exp x)) '(lit-exp 2))) (test* "(subst 'x '(lambda-exp y (var-exp y)) '(lit-exp 2))" '(lambda-exp y (var-exp y)) (substitute 'x '(lambda-exp y (var-exp y)) '(lit-exp 2))) (test* "(subst 'x '(+ x 2) 3)" '(primapp-exp + (lit-exp 3) (lit-exp 2)) (substitute 'x '(primapp-exp + (var-exp x) (lit-exp 2)) '(lit-exp 3))) (test* "(subst 'x '(+ y 2) 3)" '(primapp-exp + (var-exp y) (lit-exp 2)) (substitute 'x '(primapp-exp + (var-exp y) (lit-exp 2)) '(lit-exp 3))) (test* "(subst 'x '(a x) 2)" '(app-exp (var-exp a) (lit-exp 2)) (substitute 'x '(app-exp (var-exp a) (var-exp x)) '(lit-exp 2))) (test* "(subst 'x '((lambda (x) x) 2) 3)" '(app-exp (lambda-exp x (var-exp x)) (lit-exp 2)) (substitute 'x '(app-exp (lambda-exp x (var-exp x)) (lit-exp 2)) '(lit-exp 3))) (test* "(subst 'x '((lambda (y) y) x) 3)" '(app-exp (lambda-exp y (var-exp y)) (lit-exp 3)) (substitute 'x '(app-exp (lambda-exp y (var-exp y)) (var-exp x)) '(lit-exp 3))) (test* "(subst 'x '(x y) 'z)" '(app-exp (var-exp z) (var-exp y)) (substitute 'x '(app-exp (var-exp x) (var-exp y)) '(var-exp z))) (test-end)
beta 簡約の試験な出力は以下で。
<beta-reduction>--------------------------------------------------------------- test (beta (x 2), expects (app-exp (var-exp x) (lit-exp 2)) ==> ok test (beta ((lambda (x) 1) x)), expects (lit-exp 1) ==> ok test (beta ((lambda (x) x) 1)), expects (lit-exp 1) ==> ok test (beta ((lambda (x) (lambda (x) x)) 1)), expects (lambda-exp x (var-exp x)) ==> ok test (beta ((lambda (x) (lambda (x) y)) 1)), expects (lambda-exp x (var-exp y)) ==> ok test (beta ((lambda (x) (lambda (y) x)) 1)), expects (lambda-exp y (lit-exp 1)) ==> ok test (beta ((lambda (x) (lambda (y) y)) 1)), expects (lambda-exp y (var-exp y)) ==> ok test (beta ((lambda (x) (+ x 1)) 1)), expects (primapp-exp + (lit-exp 1) (lit-exp 1)) ==> ok test (beta ((lambda (x) (+ y 1)) 1)), expects (primapp-exp + (var-exp y) (lit-exp 1)) ==> ok test (beta ((lambda (x) (w x)) 1)), expects (app-exp (var-exp w) (lit-exp 1)) ==> ok test (beta ((lambda (x) ((lambda (x) x) 2)) 3)), expects (app-exp (lambda-exp x (var-exp x)) (lit-exp 2)) ==> ok test (beta ((lambda (x) ((lambda (y) y) x)) 3)), expects (app-exp (lambda-exp y (var-exp y)) (lit-exp 3)) ==> ok test (beta ((lambda (x) (x y)) z)), expects (app-exp (var-exp z) (var-exp y)) ==> ok <substitute>------------------------------------------------------------------- test (subst 'x '(lit-exp 1) (lit-exp 2)), expects (lit-exp 1) ==> ok test (subst 'x '(var-exp x) (lit-exp 2)), expects (lit-exp 2) ==> ok test (subst 'y '(var-exp x) (lit-exp 2)), expects (var-exp x) ==> ok test (subst 'x '(lambda-exp x (var-exp x)) '(lit-exp 2)), expects (lambda-exp x (var-exp x)) ==> ok test (subst 'x '(lambda-exp x (var-exp y)) '(lit-exp 2)), expects (lambda-exp x (var-exp y)) ==> ok test (subst 'x '(lambda-exp y (var-exp x)) '(lit-exp 2)), expects (lambda-exp y (lit-exp 2)) ==> ok test (subst 'x '(lambda-exp y (var-exp y)) '(lit-exp 2)), expects (lambda-exp y (var-exp y)) ==> ok test (subst 'x '(+ x 2) 3), expects (primapp-exp + (lit-exp 3) (lit-exp 2)) ==> ok test (subst 'x '(+ y 2) 3), expects (primapp-exp + (var-exp y) (lit-exp 2)) ==> ok test (subst 'x '(a x) 2), expects (app-exp (var-exp a) (lit-exp 2)) ==> ok test (subst 'x '((lambda (x) x) 2) 3), expects (app-exp (lambda-exp x (var-exp x)) (lit-exp 2)) ==> ok test (subst 'x '((lambda (y) y) x) 3), expects (app-exp (lambda-exp y (var-exp y)) (lit-exp 3)) ==> ok test (subst 'x '(x y) 'z), expects (app-exp (var-exp z) (var-exp y)) ==> ok passed.
次は eta-conversion なんですが no plan ッス。