Exercise 4.75: Implement for the query language
a new special form called unique. Unique should succeed if there
is precisely one item in the data base satisfying a specified query. For
example,
(unique (job ?x (computer wizard)))
should print the one-item stream
(unique (job (Bitdiddle Ben)
(computer wizard)))
since Ben is the only computer wizard, and
(unique (job ?x (computer programmer)))
should print the empty stream, since there is more than one computer
programmer. Moreover,
(and (job ?x ?j)
(unique (job ?anyone ?j)))
should list all the jobs that are filled by only one person, and the people who
fill them.
There are two parts to implementing unique. The first is to write a
procedure that handles this special form, and the second is to make
qeval dispatch to that procedure. The second part is trivial, since
qeval does its dispatching in a data-directed way. If your procedure is
called uniquely-asserted, all you need to do is
(put 'unique 'qeval uniquely-asserted)
and qeval will dispatch to this procedure for every query whose
type (car) is the symbol unique.
The real problem is to write the procedure uniquely-asserted. This
should take as input the contents (cdr) of the unique
query, together with a stream of frames. For each frame in the stream, it
should use qeval to find the stream of all extensions to the frame that
satisfy the given query. Any stream that does not have exactly one item in it
should be eliminated. The remaining streams should be passed back to be
accumulated into one big stream that is the result of the unique query.
This is similar to the implementation of the not special form.
Test your implementation by forming a query that lists all people who supervise
precisely one person.
练习 4.75:为查询语言实现一种名为 unique 的新特殊形式。unique 应在数据库中恰好有一项满足指定查询时成功。例如,
(unique (job ?x (computer wizard)))
应打印出单元素流
(unique (job (Bitdiddle Ben)
(computer wizard)))
因为 Ben 是唯一的计算机奇才;而
(unique (job ?x (computer programmer)))
应打印出空流,因为计算机程序员不止一人。此外,
(and (job ?x ?j)
(unique (job ?anyone ?j)))
应列出所有只有一人担任的职务以及担任该职务的人。
实现 unique 分两部分:第一部分是编写处理此特殊形式的过程,第二部分是让 qeval 分派到该过程。第二部分是简单的,因为 qeval 以数据导向方式进行分派。若你的过程名为 uniquely-asserted,只需执行
(put 'unique 'qeval uniquely-asserted)
qeval 就会将所有 car 为符号 unique 的查询分派给该过程。
真正的问题在于编写过程 uniquely-asserted。该过程应以 unique 查询的内容(cdr)和一个框架流作为输入。对流中的每个框架,它应用 qeval 找出所有满足给定查询的框架扩展流。任何不恰好含有一项的流都应被排除。剩余的流应被传递,累积为 unique 查询结果的大流。这与 not 特殊形式的实现类似。
请通过构造一个列出所有恰好只监管一人的人员的查询来测试你的实现。
(unique (job ?x (computer wizard))) (unique (job (Bitdiddle Ben)
(computer wizard))) (unique (job ?x (computer programmer))) (and (job ?x ?j)
(unique (job ?anyone ?j))) (put 'unique 'qeval uniquely-asserted)