Tags SICP

#### Exercise 4.64

Let's follow the procedure for applying rules described in section 4.4.2, to see what happens when the badly rewritten rule `outranked-by` is applied to the query issued by De Witt Aull:

First, we'll unify the query:

```(outranked-by (Bitdiddle Ben) ?who)
```

With the conclusion of the rule:

```(outranked-by ?staff-person ?boss)
```

The unification succeeds with the bindings `?staff-person -> (Bitdiddle Ben)` and `?boss -> ?who`. Now, we will evaluate the query formed by the body of the rule:

```(or (supervisor ?staff-person ?boss)
(and (outranked-by ?middle-manager ?boss)
(supervisor ?staff-person ?middle-manager))))
```

Relative to the extended frame. Consider what happens when we come to evaluate the sub-query `(outranked-by ?middle-manager ?boss)`. Again, this is a query that will match the `outranked-by` rule. Unifying it with the rule's conclusion succeeds, producing the bindings `?staff-person -> ?middle-manager` and `?boss -> ?who`. So we once again evaluate the rule's body, now with these bindings. And again, and again – this is an infinite loop.

Why didn't the original rule have this problem ?

Because the `(supervisor ?staff-person ?middle-manager)` sub-query came first in the `and`, and created bindings that narrowed the search when re-applying the `outranked-by` rule.

#### Exercise 4.65

Oliver Warbucks is listed four times because the rule matches four times over the database. I.e., there are four middle-managers of whom Oliver Warbucks is a manager. To find out who these are, we can unroll the rule:

```(and (supervisor ?middle-manager ?person)
(supervisor ?x ?middle-manager))
=>
(AND (SUPERVISOR (SCROOGE EBEN) (WARBUCKS OLIVER)) (SUPERVISOR (CRATCHET ROBERT) (SCROOGE EBEN)))
(AND (SUPERVISOR (BITDIDDLE BEN) (WARBUCKS OLIVER)) (SUPERVISOR (TWEAKIT LEM E) (BITDIDDLE BEN)))
(AND (SUPERVISOR (HACKER ALYSSA P) (BITDIDDLE BEN)) (SUPERVISOR (REASONER LOUIS) (HACKER ALYSSA P)))
(AND (SUPERVISOR (BITDIDDLE BEN) (WARBUCKS OLIVER)) (SUPERVISOR (FECT CY D) (BITDIDDLE BEN)))
(AND (SUPERVISOR (BITDIDDLE BEN) (WARBUCKS OLIVER)) (SUPERVISOR (HACKER ALYSSA P) (BITDIDDLE BEN)))
```

#### Exercise 4.66

Suppose that Ben will try to compute the sum of the salaries of the wheels in the organization:

```(qinterpret
'(and (wheel ?who)
(salary ?who ?amount)))
=>
(AND (WHEEL (WARBUCKS OLIVER)) (SALARY (WARBUCKS OLIVER) 150000))
(AND (WHEEL (WARBUCKS OLIVER)) (SALARY (WARBUCKS OLIVER) 150000))
(AND (WHEEL (BITDIDDLE BEN)) (SALARY (BITDIDDLE BEN) 60000))
(AND (WHEEL (WARBUCKS OLIVER)) (SALARY (WARBUCKS OLIVER) 150000))
(AND (WHEEL (WARBUCKS OLIVER)) (SALARY (WARBUCKS OLIVER) 150000))
```

Obviously, if Ben tries to apply the `sum` on `?amount` over these results, he'll get too much because of the duplications.

One way to circumvent this problem is to install a uniqueness filter that will filter out all the duplicates from the resulting frames produced by `qeval`.

#### Exercise 4.67

``???``

#### Exercise 4.68

```(qinterpret
'(assert!
(rule (reverse () ()))))
(qinterpret
'(assert!
(rule
(reverse ?x ?y)
(and
(append-to-form (?car) ?cdr ?x)
(append-to-form ?rev-cdr (?car) ?y)
(reverse ?cdr ?rev-cdr)))))
```

```(qinterpret
'(reverse ?x (1 2 3)))
=>
(REVERSE (3 2 1) (1 2 3))
```

But not:

```(qinterpret
'(reverse (1 2 3) ?x))
=>
*** - Program stack overflow. RESET
```

#### Exercise 4.69

```(rule (ends-with-grandson ?x)
(append-to-form ?head (grandson) ?x))

(rule ((great . ?rel) ?x ?y)
(and
(ends-with-grandson ?rel)
(?rel ?sx ?y)
(son ?x ?sx)))
```

#### Exercise 4.70

The problem with this alternative implementation is that `cons-stream` doesn't evaluate its second argument. Therefore, `THE-ASSERTIONS` will point to itself. In the original implementation, the purpose of the `let` was to force an evaluation of `THE-ASSERTIONS`, storing its pre-`set!` value in `old-assertions`.

It took me much longer than expected to solve this, because of one fact that puzzled me. I wrote a few unit tests for the logic evaluator, and ran them with the modified version. Everything worked. This was a surprise because I expected the self reference in the stream of assertions to cause an infinite loop.

The solution of this problem can teach us a lesson: complex systems are difficult to understand, test and debug. What actually happened is that all the assertions in my tests were indexable. Note that `store-assertion-in-index` in the implementation of `add-assertion!`, and the complementary `get-indexed-assertions` in `fetch-assertions` ? These do the actual job for most assertions, without ever getting to really searching in the big stream. To float this problem I wrote a few unindexable assertions1:

```(assert! ((jay bird) sam 10))
(assert! ((jay bird) tom 12))
```

Indeed, these caused an infinite loop with the alternative implementation when searched. Phew. I'm rarely as glad to see a stack overflow in my program :-)

#### Exercise 4.71

These delays can postpone infinite looping in some cases, providing more meaningful answers to the user. Consider these assertions:

```(qinterpret
'(assert! (dummy a))
'(assert! (dummy b))
'(assert! (dummy c))
'(assert! (rule (dummy ?x) (dummy ?x))))
```

The last one asserts an infinitely-recursive rule. Now, if we issue the query:

```(qinterpret
'(dummy ?who))
```

With the delays in place, we'll get:

```(DUMMY C)
(DUMMY B)
(DUMMY A)
(DUMMY C)
(DUMMY B)
(DUMMY A)
(DUMMY C)
(DUMMY B)
(DUMMY A)
...
...
```

To understand why, look at this portion of `simple-query`:

```      (stream-append-delayed
(find-assertions query-pattern frame)
(delay (apply-rules query-pattern frame))))
```

Note that the application of rules is delayed. In our case, there are valid assertions answering the query, but the rule is invalid, since trying to apply it causes an infinite loop.

Without the delay we get:

```*** - Program stack overflow. RESET
```

Without any useful output, because `simple-query` deepens more and more into the recursive rule without ever printing results.

Thanks to Flavio Cruz for suggesting this solution

#### Exercise 4.72

As the hint suggests, this is done for exactly the same reason as the original `interleave` in section 3.5.3 – for handling infinite streams. Suppose that `stream-flatmap` is called on two streams. The first is infinite, for some (maybe valid) reason. Without using `interleave`, the elements of the second stream won't be reached, ever.

#### Exercise 4.74

a.

`simple-flatten` assumes that it has a stream of streams, in which each stream is either the empty stream or a singleton stream. It has to do the following:

1. Filter out all the empty streams 2. Extract the elements from the singleton streams2 3. Stitch all those elements together into a new stream

Therefore the implementation is as follows:

```(defun simple-stream-flatmap (proc s)
(simple-flatten (stream-map proc s)))

(defun simple-flatten (stream)
(stream-map
#'stream-car
(stream-filter
(lambda (s)
(not (stream-null? s)))
stream)))
```

b.

I don't think this change will affect the system's behavior. It does not affect correctness, because the named functions indeed only generate either singleton or empty streams. Also, as far as I can see, all the tests pass.

I also don't see how it can change the order of assertions that are output from queries. `flatten-stream` that uses `interleave` creates the same elements as those created by `simple-flatten`, in the same order.

#### Exercise 4.75

```(defun uniquely-asserted (query frame-stream)
"Return only those frames for whom the query
produces a single match in the database"
(simple-stream-flatmap
(lambda (frame)
(let ((eval-stream
(qeval
(query-of-unique query)
(singleton-stream frame))))
(if (singleton-stream? eval-stream)
eval-stream
the-empty-stream)))
frame-stream))

(defun singleton-stream? (stream)
(and
(stream-car stream)

(defun query-of-unique (uniq) (car uniq))

(put-op 'unique 'qeval #'uniquely-asserted)
```

Some tests with the database:

```(qinterpret
'(unique (job ?x (computer wizard))))
=>
(UNIQUE (JOB (BITDIDDLE BEN) (COMPUTER WIZARD)))

(qinterpret
'(and (job ?x ?j) (unique (job ?anyone ?j))))
=>
(AND (JOB (AULL DEWITT) (ADMINISTRATION SECRETARY)) (UNIQUE (JOB (AULL DEWITT) (ADMINISTRATION SECRETARY))))
(AND (JOB (CRATCHET ROBERT) (ACCOUNTING SCRIVENER)) (UNIQUE (JOB (CRATCHET ROBERT) (ACCOUNTING SCRIVENER))))
(AND (JOB (SCROOGE EBEN) (ACCOUNTING CHIEF ACCOUNTANT))
(UNIQUE (JOB (SCROOGE EBEN) (ACCOUNTING CHIEF ACCOUNTANT))))
(AND (JOB (WARBUCKS OLIVER) (ADMINISTRATION BIG WHEEL))
(UNIQUE (JOB (WARBUCKS OLIVER) (ADMINISTRATION BIG WHEEL))))
(AND (JOB (REASONER LOUIS) (COMPUTER PROGRAMMER TRAINEE))
(UNIQUE (JOB (REASONER LOUIS) (COMPUTER PROGRAMMER TRAINEE))))
(AND (JOB (TWEAKIT LEM E) (COMPUTER TECHNICIAN)) (UNIQUE (JOB (TWEAKIT LEM E) (COMPUTER TECHNICIAN))))
(AND (JOB (BITDIDDLE BEN) (COMPUTER WIZARD)) (UNIQUE (JOB (BITDIDDLE BEN) (COMPUTER WIZARD))))

(qinterpret
'(and (supervisor ?peon ?boss)
(unique (supervisor ?others ?boss))))
=>
(AND (SUPERVISOR (CRATCHET ROBERT) (SCROOGE EBEN)) (UNIQUE (SUPERVISOR (CRATCHET ROBERT) (SCROOGE EBEN))))
(AND (SUPERVISOR (REASONER LOUIS) (HACKER ALYSSA P))
(UNIQUE (SUPERVISOR (REASONER LOUIS) (HACKER ALYSSA P))))
```

#### Exercise 4.76

Here's `merge-frames` that merges a pair of frames:

```(defun merge-frames (f1 f2)
(if (null f1)
f2
(let ((var (caar f1))
(val (cdar f1)))
(let ((extension (extend-if-possible var val f2)))
(if (equal extension 'failed)
'failed
(merge-frames (cdr f1) extension))))))
```

And this is `merge-frame-streams` that merges two streams of frames, using `merge-frames` for each pair:

```(defun merge-frame-streams (s1 s2)
"Tries to merge each frame of s1 with each frame
of s2. Returns the stream of successful merges."
(stream-flatmap
(lambda (f1)
(stream-filter
(lambda (f) (not (equal f 'failed)))
(stream-map
(lambda (f2)
(merge-frames f1 f2))
s2)))
s1))
```

`conjoin` can then be written thus:

```(defun conjoin (conjuncts frame-stream)
(if (empty-conjunction? conjuncts)
frame-stream
(merge-frame-streams
(qeval (first-conjunct conjuncts) frame-stream)
(conjoin (rest-conjuncts conjuncts) frame-stream))))
```

This works satisfactorily, in most cases. For example:

```(qinterpret
'(and
(job ?x ?j)
(supervisor ?x (bitdiddle ben))
(salary ?x 25000)))
=>
(AND (JOB (TWEAKIT LEM E) (COMPUTER TECHNICIAN)) (SUPERVISOR (TWEAKIT LEM E) (BITDIDDLE BEN))
(SALARY (TWEAKIT LEM E) 25000))

; the 'grandson' rule uses /and/
(qinterpret
'(grandson ?d ?w))
=>
(GRANDSON MEHUJAEL LAMECH)
(GRANDSON ENOCH MEHUJAEL)
```

However, there are also problems. For example, consider this:

```(qinterpret
'(and
(job ?x ?j)
(not (supervisor ?x (bitdiddle ben)))))
=>
```

It should have printed out many items, but it doesn't. This is because of the problem with `not` described in section 4.4.3; `not` needs something to filter, and the new implementation of `conjoin` simply runs it on the full input frame stream, and merges the result.

A more serious error with this approach happens when resursive rules are used. When this rule is added to the Biblical hierarchy database:

```(qinterpret
'(assert!
(rule (son ?m ?s)
(and
(wife ?m ?w)
(son ?w ?s)))))
```

The evaluator goes into an infinite loop when matching `son` rules. This is because the `son` rule invokes another `son` rule in the `and` expression, and with the new implementation of `conjoin` this call is not on a reduced set of frames.

I suppose the authors didn't make a mistake with their suggestion, but it's rather a problem with my implementation. I'll be glad if someone points me to it.

1 In the authors' implementation, an assertion is indexable if its first element is either a constant or a variable name, but not a list.

2 Recall that a singleton stream is simply an element wrapped up as a stream.