すみません、バグってました。下のほうの追記読んでください。
いろいろ忙しくて1週間くらい考えてました。
こういう問題やっとくと、なんとなくわかっていたつもりだったのが、実はぜんぜんわかってないことに気づいたりするので、できる限りは手を出すようにしてます。
frameを引き継いでマッチをかけていく方式から、別々にマッチしたフレームを矛盾がなければ混ぜ合わせる方式にするという問題。
方針は結構最初の方から頭にあって
1.2つのフレームの片方にしかない変数は無条件でマージしてよい
2.両方のフレームにある変数について
2-1.そのvalueが変数でない場合は単純に比較する
2-1-1.一致した場合はマージしてよい
2-1-2.一致しなかった場合はフレームは矛盾しており、マージはできないとみなす
2-2.そのvalueがまた変数だった場合は、そのバインドを探してまた比較する
てな感じに考えていたんですが、いざこれを実装しようとすると、本文のようなシンプルかつ綺麗にいかず苦心しました。
以下ソース
; andその2
(define (conjoin2 conjuncts frame-stream)
(if (empty-conjunction? conjuncts)
frame-stream
(let ((join1 (qeval (first-conjunct conjuncts)
frame-stream))
(join2 (conjoin2 (rest-conjuncts conjuncts)
frame-stream)))
(stream-flatmap (lambda (frame1)
(stream-flatmap (lambda (frame2)
(let ((result (merge-frame frame1 frame2)))
(if (eq? result 'false)
the-empty-stream
(singleton-stream result))))
join2))
join1))))
(define (merge-frame frame1 frame2)
(if (null? frame1)
frame2
(let ((binding (first-binding frame1)))
(let ((var (binding-variable binding))
(val (binding-value binding)))
(let ((binding2 (binding-in-frame var frame2)))
(if binding2
(let ((match-result (merge-possible? val frame1
(binding-value binding2) frame2)))
(if match-result
(merge-frame (rest-bindings frame1) frame2)
'false))
(merge-frame (rest-bindings frame1)
(extend var val frame2))))))))
(define (merge-possible? val1 frame1 val2 frame2)
(cond ((equal? val1 val2) true)
((var? val1)
(let ((binding (binding-in-frame val1 frame1)))
(if binding
(merge-possible? (binding-value binding) frame1
val2 frame2)
(merge-possible? (contract-question-mark val1) frame1
val2 frame2))))
((var? val2)
(let ((binding (binding-in-frame val2 frame2)))
(if binding
(merge-possible? val1 frame1
(binding-value binding) frame2)
(merge-possible? val1 frame1
(contract-question-mark val2) frame2))))
((and (pair? val1) (pair? val2))
(and (merge-possible? (car val1) frame1
(car val2) frame2)
(merge-possible? (cdr val1) frame1
(cdr val2) frame2)))
(else
false)))
(put 'and 'qeval conjoin2)
一応、簡単な質問
(and (address ?x ?y) (supervisor ?x ?z))
とか
(and (job ?p (computer programmer)) (salary ?p ?amo) (supervisor ?p ?sv))
みたいなのには答えられたのですが、悲しいかなruleが全然動きません。
(lives-near (Bitdiddle Ben) ?x)
ですら無理です。
(rule (lives-near ?person-1 ?person-2)
(and (address ?person-1 (?town . ?rest1))
(address ?person-2 (?town . ?rest2))
(not (same ?person-1 ?person-2))))
で、まあ上のを眺めていて気づいたんですが、よく考えたらnotを単独で処理したって結果返ってくるわけないんですよね。あと、
(rule (reverse (?x . ?y) ?z)
(and (reverse ?y ?u)
(append-to-form ?u (?x) ?z)))
これも(reverse (1 2) ?x)に答えようとした場合、(append-to-form ?u (1) ?z)に答えないといけないわけで、これを単独で実行しても結果が返ってこないんですよね(私の環境ではそうでした)。
と、いうところで心が折れました。
まあ、一応簡単なのには答えられたからいいかなーっと思ってます。
最近のコメント