EoPL reading (123) 2.3 Representation Strategies for Data Types

Exercise 2.25

unify-terms を検討。

  • ts と us が両方同時に '() なら (empty-subst) を戻す
  • ts あるいは us のどちらかが '() なら #f を戻す

以下。

(test* "(unify-terms '() '())"
       '(empty-subst-rec)
       (unify-terms '() '()))

(test* "(unify-terms '() '(var-term a))"
       #f
       (unify-terms '() '(var-term a)))

(test* "(unify-terms '(var-term a) '())"
       #f
       (unify-terms '(var-term a) '()))

試験は無論パス。問題はここから先。

  • 引数リストの両方の car を unify-term して subst-car に
  • subst-car が #f なら #f 戻して終了

で、その後なんですが以下。

  • 引数リストの cdr と subst-car を subst-in-terms に渡してそれぞれ new-ts, new-us に
  • new-ts と new-us を unify-terms にして戻りを subst-cdr に
    • これ、残りを置き換えとくイメージですか

むむ。再帰してないってカン違いしてましたが、ここで再帰呼び出しか。ざっくりここで cdr 要素について掘り下げてって最終的に compose-subst するのか。ちょっとイメージし辛いので若干ズルを。unify-term を見るに、引数の両方が app-term だった場合に、unify-terms が呼び出されているのが分かる。
以下を例にしてトレイスしてみます。

(unify-term '(app-term ((var-term x) (constant-term 1)))
            '(app-term ((var-term y) (constant-term 2))))

これはまず、(var-term x) と (var-term y) を unify-term して

(extend-subst-rec x (var-term y) (empty-subst))

が戻る。これは subst-car にセットされる。次に上記の substitution と リストの cdr 要素を渡して subst-in-terms が呼び出されて

((constant-term 1))

とか

((constant-term 2))

とかが戻ってくる。これが new-ts とか new-us とか。で、unify-term に渡されるのですが、これがダウトで #f が戻ってきます。失敗。
両方同じ値でリトライ。片方をもう片方に合わせるとすると、unify-terms の中の unify-term な呼び出しにより (empty-subst) が戻る。正確には (empty-subst-rec) です。
てーコトは compose-subst に渡されるのは

subst-car が (extend-subst-rec x (var-term y) (empty-subst))
subst-cdr が (empty-subst)

になる。それで compose なのか。subst-car の末端要素が subst-cdr にならないと駄目という読み。

(list (car subst-car) (cadr subst-car) (caddr subst-car) subst-cdr)

を戻せば良さげに見えますがイージー杉でしょうか。再帰なナニを見るに、

  • subst-car には引数の car 要素の substitution が格納
    • 基本的に末端は (empty-subst) なナニになってるはず
  • subst-cdr には (empty-subst) まで遡って順に substitution が作られてく
    • extend-subst-rec なリストの末端要素は substitution なオブジェクト

って意味解りにくい。下記のリストだとどうか。

(unify-term '(app-term ((var-term x) (var-term z)))
            '(app-term ((var-term y) (var-term a))))

これ、以下が戻るはずなんですがダウトかなぁ。

(extend-subst-rec x
                  (var-term y)
		  (extend-subst-rec z
                                    (var-term a)
                                    (empty-subst-rec)))

なんなくイケてそうなカンジですが眠くて思考力が落ちてます。記憶も朧なんですが、以下な試験を投入。

(test* "(unify-terms '((var-term a) (constant-term 1))
                     '((var-term b) (constant-term 2)))"
       #f
       (unify-terms '((var-term a) (constant-term 1))
                     '((var-term b) (constant-term 2))))

(test* "(unify-terms '((var-term a) (constant-term 1))
                     '((var-term b) (constant-term 1)))"
       '(extended-subst-rec a (var-term b) (empty-subst-rec))
       (unify-terms '((var-term a) (constant-term 1))
		    '((var-term b) (constant-term 1))))

(test* "(unify-terms '((var-term x) (var-term z))
                     '((var-term y) (var-term a)))"
       '(extended-subst-rec x 
			    (var-term y)
			    (extended-subst-rec z
						(var-term a)
						(empty-subst-rec)))
       (unify-terms '((var-term x) (var-term z))
		    '((var-term y) (var-term a))))

二番目のソレが失敗します。

got #<error "pair required, but got ()"

うーむ。目視では (empty-subst-rec) が二重になってるから、か。

(compose-subst (empty-subst-rec) (empty-subst-rec))

は NG ですな。てコトは卑怯なニゲ方は以下か。

(define compose-subst
  (lambda (s1 s2)
    (if (eqv? s1 '(empty-subst-rec))
	s1
	(list (car s1) (cadr s1) (caddr s1) s2))))

これは非道。でも試験にパスしない。どうも if な条件式が微妙だった模様。

(define compose-subst
  (lambda (s1 s2)
    (if (eqv? 'empty-subst-rec (car s1))
	s1
	(list (car s1) (cadr s1) (caddr s1) s2))))

今日はへろへろなので残り (試験?) は明日。