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


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




[127]

Продолжение успеха представляет собой процедуру от двух аргументов: только что полученного значения и продолжения неудачи, которое нужно будет применить, если обработка значения впоследствии приведет к неудаче. Продолжение неудачи представляет собой процедуру без аргументов. Таким образом, общая форма исполнительной процедуры такова:

(lambda (env succeed fail)

;; succeed выглядит как (lambda (value fail) ...) ;; fail выглядит как (lambda () ...) ...)

Например,

(ambeval (выражение)

the-global-environment (lambda (value fail) value)

(lambda () failed))

попытается вычислить данное выражение, и вернет либо его значение (если вычисление будет успешным), либо символ failed (если вычисление потерпит неудачу). Вызов ambeval в нижеприведенном управляющем цикле использует намного более сложные процедуры продолжения, которые возвращаются к выполнению цикла и поддерживают запрос try-again.

Сложность amb-интерпретатора по большей части заключается в механизмах передачи продолжений, когда исполнительные процедуры вызывают друг друга. Читая код в этом разделе, следует сравнивать каждую исполнительную процедуру с соответствующей процедурой обыкновенного интерпретатора из раздела 4.1.7.

Простые выражения

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

(define (analyze-self-evaluating exp) (lambda (env succeed fail) (succeed exp fail)))

(define (analyze-quoted exp)

(let ((qval (text-of-quotation exp))) (lambda (env succeed fail) (succeed qval fail))))

(define (analyze-variable exp) (lambda (env succeed fail)

(succeed (lookup-variable-value exp env)

fail)))

(define (analyze-lambda exp)

(let ((vars (lambda-parameters exp))


(bproc (analyze-sequence (lambda-body exp)))) (lambda (env succeed fail)

(succeed (make-procedure vars bproc env)

fail))))

Заметим, что поиск переменной всегда «успешен». Если процедуре lookup-variable-value не удается найтизначение, она, как обычно, сообщает об ошибке. Такая «неудача» означает ошибку в программе: ссылку на несвязанную переменную; это не означает, что нам нужно пробовать какой-либо другой вариант недетерминистского выбора вместо того, который исполняется сейчас.

Условные выражения и последовательности

Обработка условных выражений также похожа на соответствующий процесс в обычном интерпретаторе. Исполнительная процедура, порождаемая в analyze-if, зовет исполнительную процедуру предиката pproc с продолжением успеха, которое, проверив, истинно ли значение предиката, в соответствии с этим выполняет либо следствие, либо альтернативу. Если выполнение pproc терпит неудачу, вызывается исходное продолжение неудачи, переданное в выражение if.

(define (analyze-if exp)

(let ((pproc (analyze (if-predicate exp))) (cproc (analyze (if-consequent exp))) (aproc (analyze (if-alternative exp)))) (lambda (env succeed fail) (pproc env

;; продолжение успеха при вычислении предиката ;; и получении pred-value (lambda (pred-value fail2) (if (true? pred-value)

(cproc env succeed fail2) (aproc env succeed fail2))) ;; продолжение неудачи при вычислении предиката

fail))))

Последовательности тоже обрабатываются так же, как и в предыдущем интерпретаторе, если не считать махинаций в подпроцедуре sequentially, которые требуются для передачи продолжений. А именно, чтобы выполнить последовательно a и b, мы вызываем a с продолжением успеха, вызывающим b.

(define (analyze-sequence exps) (define (sequentially a b) (lambda (env succeed fail) (a env

;; продолжение успеха при вызове a (lambda (a-value fail2) (b env succeed fail2)) ;; продолжение неудачи при вызове a

fail)))

(define (loop first-proc rest-procs) (if (null? rest-procs) first-proc

(loop (sequentially first-proc (car rest-procs))


(cdr rest-procs)))) (let ((procs (map analyze exps))) (if (null? procs)

(error "Пустая последовательность -- ANALYZE")) (loop (car procs) (cdr procs))))

Определения и присваивания

Определения - еще один случай, когда обработка продолжений сопряжена с известными трудностями, поскольку требуется сначала вычислить выражение, которое будет значением определяемой переменной, а затем уже ее собственно определить. Ради этого процедура вычисления значения vproc вызывается со следующими аргументами: окружение, продолжение успеха и продолжение неудачи. Если вычисление vproc происходит успешно и дает значение val для определяемой переменной, то переменная определяется и успех распространяется далее:

(define (analyze-definition exp)

(let ((var (definition-variable exp))

(vproc (analyze (definition-value exp)))) (lambda (env succeed fail) (vproc env

(lambda (val fail2)

(define-variable! var val env) (succeed ok fail2))

fail))))

Присваивания устроены интереснее. Это первый случай, когда мы действительно используем продолжения, а не просто передаем их из процедуры в процедуру. Исполнительная процедура для присваивания начинается так же, как и процедура для определения. Сначала она пытается получить новое значение, которое надо присвоить переменной. Если вычисление vproc терпит неудачу, неудачно и все присваивание.

Однако если vproc выполняется удачно, и мы действительно выполняем присваивание, то нам нужно рассмотреть возможность, что текущая ветка вычисления позже, может быть, приведет к неудаче. Тогда нам понадобится откатиться к моменту до присваивания. Таким образом, нам нужно уметь отменить

57

присваивание в процессе возврата.57

Этого мы добиваемся, передавая vproc продолжение успеха (отмеченное ниже комментарием «*/*»), которое сохраняет старое значение переменной, прежде чем присвоить ей новое значение и продолжить вычисление. Продолжение неудачи, которое передается вместе со значением присваивания (и отмечено ниже комментарием «*2*»), восстанавливает старое значение переменной, прежде чем продолжить откат. То есть, успешное присваивание дает продолжение неудачи, которое перехватит последующую неудачу; неудача, которая в противном случае вызвала бы fail2, вместо этого зовет эту процедуру, а она отменяет присваивание и уже затем зовет fail2.

(define (analyze-assignment exp)

(let ((var (assignment-variable exp))

57Мы не заботились об отмене определений, поскольку можно предположить, что внутренние определения изымаются (раздел 4.1.6).



[стр.Начало] [стр.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]