Ex. 4.74
a.
negate の例を考える。
(and (supervisor ?x (Warbucks Oliver)) (not (same ?x (Scrooge Eben))))
最初の (supervisor ?x (Warbucks Oliver)) で作られるフレームストリームは
[ {(?x . (Aull DeWitt))} {(?x . (Scrooge Eben))} {(?x . (Bitdiddle Ben))} ]
である。( )は変数束縛、{ } はフレーム、[ ] はフレームストリームとする。
次の (not ...) は negate 関数を呼び出す。
(negate '((same ?x (Scrooge Eben))) '[ {(?x . (Aull DeWitt))} {(?x . (Scrooge Eben))} {(?x . (Bitdiddle Ben))} ] )
negateの最初の引数には (not (same...))の cdr が渡されるので、((same ...)) とカッコが2重になっている。
negate の定義に simple-stream-flatmap を使った場合の動作
(negate '((same ?x (Scrooge Eben))) '[ {(?x . (Aull DeWitt))} {(?x . (Scrooge Eben))} {(?x . (Bitdiddle Ben))} ] ) ↓ (simple-stream-flatmap (lambda (frame) (if (stream-null? (qeval (negated-query '((same ?x (Scrooge Eben)))) (singleton-stream frame))) (singleton-stream frame) the-empty-stream)) '[ {(?x . (Aull DeWitt))} {(?x . (Scrooge Eben))} {(?x . (Bitdiddle Ben))} ] )) ↓ (simple-flatten (stream-map (lambda (frame) (if (stream-null? (qeval '(same ?x (Scrooge Eben)) (singleton-stream frame))) (singleton-stream frame) the-empty-stream)) '[ {(?x . (Aull DeWitt))} {(?x . (Scrooge Eben))} {(?x . (Bitdiddle Ben))} ] ))) ↓ map の適用。 1個目のフレーム {(?x . (Aull DeWitt))} の結果は [ {(?x . (Aull DeWitt))} ] 2個目のフレーム {(?x . (Scrooge Eben))} の結果は the-empty-stream 3個目のフレーム {(?x . (Bitdiddle Ben))} の結果は [ {(?x . (Bitdiddle Ben))} ] 結局 map の結果は [ [{(?x . (Aull DeWitt))}] the-empty-stream [{(?x . (Bitdiddle Ben))}] ] というストリームのストリームになる。 negateはストリームを増やすことはないので、 ストリームの中のストリームはシングルトンストリームまたは the-empty-stream のみである。 ↓ (simple-flatten `[ [{(?x . (Aull DeWitt))}] ,the-empty-stream [{(?x . (Bitdiddle Ben))}] ] ) ↓ (stream-map <??>① (stream-filter <??>② `[ [{(?x . (Aull DeWitt))}] ,the-empty-stream [{(?x . (Bitdiddle Ben))}] ] ))
となる。( `はquasiquote , はunquote。実験するときは注意。)
ここまでくれば、<??>② は the-empty-stream を取り除くフィルターであり、<??>①はストリームの中のシングルトンストリームをフレームに下げる関数。要するに car であると分かる。
ということで答えは
(define (simple-flatten stream) (stream-map (lamda (x) (car x)) (stream-filter (lambda (x) (not (eq? x the-empty-stream))) stream)))
b.
この問題の negate の場合
(negate '((same ?x (Scrooge Eben))) '[ {(?x . (Aull DeWitt))} {(?x . (Scrooge Eben))} {(?x . (Bitdiddle Ben))} ] ) ↓ [ {(?x . (Aull DeWitt))} . (delay {(?x . (Bitdiddle Ben))}) ]
既存の negate の場合
(negate '((same ?x (Scrooge Eben))) '[ {(?x . (Aull DeWitt))} {(?x . (Scrooge Eben))} {(?x . (Bitdiddle Ben))} ] ) ↓ [ {(?x . (Aull DeWitt))} . (delay {(?x . (Bitdiddle Ben))}) ]
となる。(flatten-streamは一見 the-empty-stream をフィルタしてないように見えるが、下位関数のinterleave-delyed が the-empty-stream を読み飛ばしている。)
ということで、結果のストリームはどちらも同じである。(当たり前か。結果変わってたら提案以前のバグだ。)
delayのタイミングについても、この問題の negate は入力ストリームの2個目以降の処理を遅延する。既存の negate も同じである。
ということで、他になんか?何もなければ、negate については、特に振る舞いは変わらないような気がする。
lisp-value, find-assertionsについては、、、疲れたので略。