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については、、、疲れたので略。