Ремонт принтеров, сканнеров, факсов и остальной офисной техники


назад Оглавление вперед




[138]

(cond ((assertion-to-be-added? q)

(add-rule-or-assertion! (add-assertion-body q)) (newline)

(display "Утверждение добавлено в базу данных.") (query-driver-loop)) (else (newline)

(display output-prompt) (display-stream (stream-map (lambda (frame) (instantiate q

frame

(lambda (v f)

(contract-question-mark v)))) (qeval q (singleton-stream ())))) (query-driver-loop)))))

Здесь, как и в других интерпретаторах из этой главы, мы пользуемся абстрактным синтаксисом языка запросов. Реализация синтаксиса выражений, включая предикат assertion-to-be-added? и селектор add-assertion-body, дается в разделе 4.4.4.7. Процедура add-rule-or-assertion! определяется в разделе 4.4.4.5.

Прежде чем обрабатывать входное выражение, управляющий цикл преобразует его синтаксис в форму, которая делает обработку эффективнее. При этом меняется представление переменных образца. Когда запрос конкретизируется, то все переменные, которые остались несвязанными, преобразуются, прежде чем печататься, обратно во входное представление. Эти преобразования производятся процедурами query-syntax-process и contract-questionmark (раздел 4.4.4.7).

Чтобы конкретизировать выражение, мы его копируем, заменяя при этом все переменные выражения их значениями из данного кадра. Значения сами по себе конкретизируются, поскольку и они могут содержать переменные (например, если ?x внутри exp связано в результате унификации со значением ?y, а уже ?y связано со значением 5). Действие, которое требуется предпринять, если переменную не удается конкретизировать, задается процедурным аргументом instantiate.

(define (instantiate exp frame unbound-var-handler) (define (copy exp) (cond ((var? exp)

(let ((binding (binding-in-frame exp frame))) (if binding

(copy (binding-value binding)) (unbound-var-handler exp frame)))) ((pair? exp)

(cons (copy (car exp)) (copy (cdr exp)))) (else exp)))

(copy exp))

Процедуры, управляющие связываниями, определяются в разделе 4.4.4.8.


4.4.4.2 Вычислитель

Процедура qeval, вызываемая из query-driver-loop, является основным вычислителем запросной системы. Она принимает на входе запрос и поток кадров и возвращает поток расширенных кадров. Особые формы она распознает через диспетчеризацию, управляемую данными, при помощи get и put, в точности так же, как мы реализовывали обобщенные операции в главе 2. Все запросы, которые не распознаются как особая форма, считаются простыми запросами и обрабатываются процедурой simple-query.

(define (qeval query frame-stream)

(let ((qproc (get (type query) qeval))) (if qproc

(qproc (contents query) frame-stream) (simple-query query frame-stream))))

Селекторы type и contents, определяемые в разделе 4.4.4.7, реализуют абстрактный синтаксис особых форм.

Простые запросы

Процедура simple-query обрабатывает простые запросы. В качестве аргументов она принимает простой запрос (образец) и поток кадров, а возвращает поток, порожденный путем расширения каждого кадра всеми результатами успешного сопоставления записей базы данных с запросом.

(define (simple-query query-pattern frame-stream) (stream-flatmap (lambda (frame)

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

Для каждого кадра из входного потока мы с помощью find-assertions (раздел 4.4.4.3) сопоставляем образец со всеми утверждениями из базы данных, получая при этом поток расширенных кадров. Кроме того, с помощью apply-rules (раздел 4.4.4.4) мы применяем все подходящие правила и получаем при этом еще один поток расширенных кадров. Два этих потока сливаются (при помощи stream-append-delayed из раздела 4.4.4.6) и дают на выходе поток, перечисляющий все способы, которыми исходный запрос можно удовлетворить в соответствии с исходным кадром (см. упражнение 4.71). Потоки от отдельных входных кадров соединяются через stream-flatmap (раздел 4.4.4.6) в один большой поток, содержащий все способы, которыми можно расширить кадры из входного потока и получить сопоставление с исходным запросом.

Составные запросы

Запросы с операцией and обрабатываются так, как показано на рис. 4.5, процедурой conjoin. Conjoin принимает в качестве аргументов конъюнкты и поток кадров, а возвращает поток расширенных кадров. Сначала она обрабатывает поток кадров и получает поток всех их возможных расширений, удовлетворяющих первому запросу конъюнкции. Затем, используя этот новый поток кадров, она рекурсивно применяет conjoin к остальным конъюнктам.


(define (conjoin conjuncts frame-stream) (if (empty-conjunction? conjuncts) frame-stream

(conjoin (rest-conjuncts conjuncts)

(qeval (first-conjunct conjuncts) frame-stream))))

Выражение

(put and qeval conjoin)

настраивает процедуру qeval так, чтобы она при обнаружении формы and вызывала conjoin.

Запросы or обрабатываются подобным же образом, как показано на рис. 4.6. Выходные потоки отдельных дизъюнктов or вычисляются раздельно и смешиваются при помощи процедуры interleave-delayed из раздела 4.4.4.6. (См. упражнения 4.71 и 4.72.)

(define (disjoin disjuncts frame-stream) (if (empty-disjunction? disjuncts) the-empty-stream (interleave-delayed (qeval (first-disjunct disjuncts) frame-stream) (delay (disjoin (rest-disjuncts disjuncts) frame-stream)))))

(put or qeval disjoin)

Предикаты и селекторы для синтаксиса конъюнктов и дизъюнктов даны в разделе 4.4.4.7.

Фильтры

Запросы not обрабатываются так, как описано в разделе 4.4.2. Мы пытаемся расширить каждый кадр входного потока так, чтобы удовлетворялся отрицаемый запрос, и включаем данный кадр в поток-результат только в том случае, если расширить его нельзя.

(define (negate operands frame-stream) (stream-flatmap (lambda (frame)

(if (stream-null? (qeval (negated-query operands)

(singleton-stream frame))) (singleton-stream frame) the-empty-stream)) frame-stream))

(put not qeval negate)

Lisp-value - фильтр, подобный not. Образец расширяется с помощью каждого кадра из входного потока, применяется указанный предикат, и кадры, для которых он возвращает ложное значение, исключаются из входного потока. Если остаются несвязанные переменные запроса, возникает ошибка.



[стр.Начало] [стр.1] [стр.2] [стр.3] [стр.4] [стр.5] [стр.6] [стр.7] [стр.8] [стр.9] [стр.10] [стр.11] [стр.12] [стр.13] [стр.14] [стр.15] [стр.16] [стр.17] [стр.18] [стр.19] [стр.20] [стр.21] [стр.22] [стр.23] [стр.24] [стр.25] [стр.26] [стр.27] [стр.28] [стр.29] [стр.30] [стр.31] [стр.32] [стр.33] [стр.34] [стр.35] [стр.36] [стр.37] [стр.38] [стр.39] [стр.40] [стр.41] [стр.42] [стр.43] [стр.44] [стр.45] [стр.46] [стр.47] [стр.48] [стр.49] [стр.50] [стр.51] [стр.52] [стр.53] [стр.54] [стр.55] [стр.56] [стр.57] [стр.58] [стр.59] [стр.60] [стр.61] [стр.62] [стр.63] [стр.64] [стр.65] [стр.66] [стр.67] [стр.68] [стр.69] [стр.70] [стр.71] [стр.72] [стр.73] [стр.74] [стр.75] [стр.76] [стр.77] [стр.78] [стр.79] [стр.80] [стр.81] [стр.82] [стр.83] [стр.84] [стр.85] [стр.86] [стр.87] [стр.88] [стр.89] [стр.90] [стр.91] [стр.92] [стр.93] [стр.94] [стр.95] [стр.96] [стр.97] [стр.98] [стр.99] [стр.100] [стр.101] [стр.102] [стр.103] [стр.104] [стр.105] [стр.106] [стр.107] [стр.108] [стр.109] [стр.110] [стр.111] [стр.112] [стр.113] [стр.114] [стр.115] [стр.116] [стр.117] [стр.118] [стр.119] [стр.120] [стр.121] [стр.122] [стр.123] [стр.124] [стр.125] [стр.126] [стр.127] [стр.128] [стр.129] [стр.130] [стр.131] [стр.132] [стр.133] [стр.134] [стр.135] [стр.136] [стр.137] [стр.138] [стр.139] [стр.140] [стр.141] [стр.142] [стр.143] [стр.144] [стр.145] [стр.146] [стр.147] [стр.148] [стр.149] [стр.150] [стр.151] [стр.152] [стр.153] [стр.154] [стр.155] [стр.156] [стр.157] [стр.158] [стр.159] [стр.160] [стр.161] [стр.162] [стр.163] [стр.164] [стр.165] [стр.166] [стр.167] [стр.168] [стр.169] [стр.170] [стр.171] [стр.172] [стр.173] [стр.174] [стр.175] [стр.176] [стр.177] [стр.178] [стр.179] [стр.180] [стр.181] [стр.182] [стр.183] [стр.184] [стр.185] [стр.186] [стр.187] [стр.188] [стр.189] [стр.190] [стр.191] [стр.192] [стр.193] [стр.194] [стр.195] [стр.196]