Exercise 4.71. Louis Reasoner wonders why the simple-query and disjoin procedures (section 4.4.4.2) are implemented using explicit delay operations, rather than being defined as follows: (define (simple-query query-pattern frame-stream) (stream-flatmap (lambda (frame) (stream-append (find-assertions query-pattern frame) (apply-rules query-pattern frame))) frame-stream)) (define (disjoin disjuncts frame-stream) (if (empty-disjunction? disjuncts) the-empty-stream (interleave (qeval (first-disjunct disjuncts) frame-stream) (disjoin (rest-disjuncts disjuncts) frame-stream)))) Can you give examples of queries where these simpler definitions would lead to undesirable behavior? ———————————————————————————————————————————————————————————————————————— The difference is that the second arguments to stream-append and interleave are evaluated immediately, which causes the stream-car of the inner apply-rules and disjoin expressions to be evaluated. There may be infinite frame streams, in which case the delayed definitions will return an infinite stream in finite time, while Louis's disjoin will continue calling itself before returning a stream of results. There seems to be some similar problem with apply-rules, though I'm not sure of the specifics. Even in the case of finite streams, the versions which do not put a combinatorial explosion of branches in memory at once can be expected to perform better.