Ex. 4.69
greatがどんな動作をするか予想してみる。
入力 ((great grandson) Adam ?) 出力 ((great grandson) Adam Irad) ------ 入力 ((great great grandson) Adam ?) 出力 ((great great grandson) Adam Methushael)
リストの最後が grandson であることをチェックする rule の動作の予想は
入力 (grandson-ended (great grandson)) 出力 (grandson-ended (great grandson)) ------ 入力 (grandson-ended (son)) 出力 なし
こんな感じか。
規則 great の変わっているところは、規則の名前がリストになっている点である。こんな規則が本当に作れるのか?作ったとして解釈系は実行できるのか?grandsonの前に great 以外が入っていないかチェックしなくていいのか?
気になる点は多いが、とりあえず、grandson-ended から作ってみる。
(rule (grandson-ended ?x) (append-to-form ?a (grandson) ?x))
こんな感じ。
次に greatの定義は
①((grandson) a) = (grandson a) ②X = (great grandson) or (great great grandson) or ... かつ (X a)= b ならば ((cons (great X)) a) = (son b) である。
こんな感じ。公理的定義というより、ほとんど帰納的定義になっている。 ①は帰納法の初期値の定義のようなもの。
rule形式にするために、②に中間変数を入れる。
②X = (great grandson) or (great great grandson) or ... かつ (X a)= b かつ (son b) = c ならば ((cons (great X)) a) = c である。
ruleに置き換える
(rule ((grandson) ?a) (grandson ?a)) (rule ((great . ?X) ?a ?c) (and (son ?b ?c) (?X ?a ?b) (grandson-ended ?X)))
andの順番は工夫している。この順番以外、例えば grandson-ended を and の上のほうの行に置いたりすると無限ループしてしまう。
動かしてみる。
;;; Query input: ((great grandson) Adam ?) ;;; Query results: ((great grandson) Adam Irad) ------ ;;; Query input: ((great great grandson) Adam ?) ;;; Query results: ((great great grandson) Adam Mehujael) ------ ;;; Query input: ((great grandson) ?g ?ggs) ;;; Query results: ((great grandson) Irad Lamech) ((great grandson) Enoch Methushael) ((great grandson) Cain Mehujael) ((great grandson) Adam Irad) ((great grandson) Mehujael Jubal) ((great grandson) Mehujael Jabal) ------ ;;; Query input: (?relationship Adam Irad) ;;; Query results: ((great grandson) Adam Irad)
注意。最後の ?relationship の結果を得るには、Ex.4.64の無限ループする rule を DBから消しておくこと。これが残っていると、?relationship はこの rule もユニファイしようとして無限ループにはまる。(はまりました)
デバッグについて
Schemeはデバッグ機能が貧弱なので rule なんかのデバッグはとても困る。
仕方ないので apply-a-rule にデバッグプリントを入れてフレームと規則の本体を表示させている。あとは想像をたくましくするしかない。(それでも、ほとんど何が起こってるか分からない(泣)
(define (apply-a-rule rule query-pattern query-frame) (let ((clean-rule (rename-variables-in rule))) (let ((unify-result (unify-match query-pattern (conclusion clean-rule) query-frame))) (if (eq? #?=unify-result 'failed) the-empty-stream (qeval #?=(rule-body clean-rule) (singleton-stream unify-result))))))