EoPL reading (118) 2.3 Representation Strategies for Data Types

理解が微妙なまま進める、というのも手を動かし辛い。とりあえず昨晩のソレをビンゴと見てつき進むしかないな。

Exercise 2.24 のつづき

で、以下のがヒリ出てきた。なんか不調だ。

(add-load-path ".")

(load "term")

(define-datatype subst subst?
  (empty-subst-rec)
  (extended-subst-rec
   (i symbol?)
   (t term?)
   (s subst?)))

(define empty-subst
  (lambda ()
    (empty-subst-rec)))

(define extend-subst
  (lambda (i t s)
    (extended-subst-rec i t s)))

(define apply-subst
  (lambda (s i)
    (cases subst s
	   (empty-subst-rec 
	    ()
	    (eopl:error 'apply-subst
			"No binding for " sym))
	   (extended-subst-rec
	    (item term substitution)
	    (if (eqv? item i)
		term
		(var-term i))))))

試験が以下。昨晩の試験と微妙に違う。

(use gauche.test)

(add-load-path ".")
(load "substitution")

(test-start "substitution")
(test-section "empty-subst")
(test* "apply empty-subst"
       *test-error*
       (apply-subst empty-subst 'a))

(test-section "apply-subst")
(test* "apply ex-subst (var)"
       '(var-term a)
       (apply-subst (extend-subst 'x '(var-term a) empty-subst)
		    'x))
(test* "apply ex-subst (var)"
       '(var-term y)
       (apply-subst (extend-subst 'x '(var-term a) empty-subst)
		    'y))
(test* "apply ex-subst (var)"
       '(app-term (var-exp +) (var-exp x) (constant-exp 1))
       (apply-subst (extend-subst 'x '(app-term (var-exp +) (var-exp x) (constant-exp 1)) empty-subst)
		    'x))

(test-section "extend-subst")

(test-end)

異なる点は

  • empty-subst の手続きを呼び出さなくてはならない
  • 基本的に var-term しか渡されない

という事。微妙さ満点なんですが、以下の subst-in-term を実装して試験書いてみる。

(define subst-in-term
  (lambda (s t)
    (cases term t
           (constant-term (datum) datum)
           (var-term (id) (apply-subst s id))
           (app-term (terms)
                     (let f ((rslt '()) (l terms))
                       (if (null? l)
                           rslt
                           (f (append (list (subst-in-term s (car l)) rslt))
                              (cdr l))))))))

以下の試験を書いて微妙にハマる。上記実装は相当ダウト。

(test-section "subst-in-term")
(let ((s (extend-subst 'x '(var-term a) (empty-subst))))
  (test* "not subst"
	 '(constant-term 1)
	 (subst-in-term s '(constant-term 1)))
  (test* "subst"
	 '(var-term a)
	 (subst-in-term s '(var-term x)))
  (test* "not subst"
	 '(var-term y)
	 (subst-in-term s '(var-term y)))
  (test* "not subst"
	 '(app-term ((constant-term 1) (constant-term 2)))
	 (subst-in-term s '(app-term ((constant-term 1) (constant-term 2)))))
  (test* "subst"
	 '(app-term ((var-term a) (var-term y) (constant-term 1)))
	 (subst-in-term s '(app-term ((var-term x) (var-term y) (constant-term 1)))))
  )

バグってたのは以下

  • constant-term の時に datum のみ戻すのはダメで (constant-term datum) を戻す
  • app-term の処理で最終的に戻すのは rslt ではなくて (append (list 'app-term) (list rslt)) を戻す
  • l が null? でない場合、car 要素を subst-in-term した戻りは末端に append
    • しかも append の括弧が上記実装では微妙

で最終的に以下。

(define subst-in-term
  (lambda (s t)
    (cases term t
           (constant-term (datum) (constant-term datum))
           (var-term (id) (apply-subst s id))
           (app-term (terms)
                     (let f ((rslt '()) (l terms))
                       (if (null? l)
                           (append (list 'app-term) (list rslt))
                           (f (append rslt (list (subst-in-term s (car l))))
                              (cdr l))))))))

これ、次の問題込みで検討した方が良さげ。しかも EoPL 一旦休憩して SICP の図形言語方面に去ったりなんかしようと思ってます。