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


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




[111]

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

Мы включаем в интерпретатор синтаксические процедуры, которые определяют доступ к частям выражения cond, а также процедуру cond->if, которая преобразует выражения cond в выражения if. Анализ случаев начинается с cond и состоит из списка ветвей-вариантов вида предикат-действие. Вариант считается умолчательным, если его предикатом является символ else.12

(define (cond? exp) (tagged-list? exp cond))

(define (cond-clauses exp) (cdr exp))

(define (cond-else-clause? clause) (eq? (cond-predicate clause) else))

(define (cond-predicate clause) (car clause))

(define (cond-actions clause) (cdr clause))

(define (cond->if exp)

(expand-clauses (cond-clauses exp)))

(define (expand-clauses clauses) (if (null? clauses)

false; нет ветви else

(let ((first (car clauses)) (rest (cdr clauses))) (if (cond-else-clause? first)

(if (null? rest)

(sequence->exp (cond-actions first)) (error "Ветвь ELSE не последняя - COND->IF" clauses)) (make-if (cond-predicate first)

(sequence->exp (cond-actions first)) (expand-clauses rest))))))

Выражения (вроде cond), которые мы желаем реализовать через синтаксические преобразования, называются производными (derived expressions). Выражения let также являются производными (см. упражнение 4.6).13

Упражнение 4.2.

Хьюго Дум хочет переупорядочить ветви cond так, чтобы ветвь для вызова процедур располагалась перед веткой для присваивания. Он утверждает, что при этом интерпретатор станет эффективнее: поскольку в программах обычно больше вызовов процедур,

12Значение выражения cond, когда все предикаты ложны, а вариант по умолчанию else отсутствует, в языке Scheme не определено; здесь мы решили сделать его ложным.

13Практические Лисп-системы предоставляют механизм, который дает пользователю возможность добавлять новые производные выражения и определять их значения через синтаксические преобразования, не внося изменений в вычислитель. Такое преобразование, определяемое пользователем, называется макрос (macro). Добавить простой механизм для определения макросов легко, однако в получающемся языке возникают сложные проблемы конфликта имен. Множество исследований посвящено поиску механизмов определения макросов, в которых такие проблемы не возникают. См., например, Kohlbecker 1986, Clinger and Rees 1991 и Hanson 1991.


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

a.Что за ошибка содержится в плане Хьюго? (Подсказка: что сделает его интерпретатор с выражением (define x 3)?)

b.Хьюго расстроен, что его план не сработал. Он готов пойти на любые жертвы, чтобы позволить интерпретатору распознавать вызовы процедур до того, как он проверяет все остальные типы выражений. Помогите ему, изменив синтаксис интерпретируемого языка так, чтобы вызовы процедур начинались с символа call. Например, вместо (factorial 3) нам теперь придется писать (call factorial 3), а вместо (+ 1 2) - (call + 1 2).

Упражнение 4.3.

Перепишите eval так, чтобы диспетчеризация происходила в стиле, управляемом данными. Сравните результат с дифференцированием, управляемым данными, из упражнения 2.73. (Можно использовать car составного выражения в качестве типа этого выражения, так как это хорошо сочетается с синтаксисом, реализованным в этом разделе.)

Упражнение 4.4.

Вспомним определения особых форм and и or из главы 1:

•and: выражения вычисляются слева направо. Если значение какого-то из них оказывается ложным, возвращается ложь; оставшиеся выражения не вычисляются. Если все выражения оказываются истинными, возвращается значение последнего из них. Если нет ни одного выражения, возвращается истина.

•or: выражения вычисляются слева направо. Если значение какого-то из них оказывается истинным, возвращается это значение; оставшиеся выражения не вычисляются. Если все выражения оказываются ложными, или нет ни одного выражения, возвращается ложь.

Введите and и or в качестве новых особых форм интерпретатора, определив соответствующие синтаксические процедуры и процедуры выполнения eval-and и eval-or. В качестве альтернативы покажите, как можно реализовать and и or в виде производных выражений.

Упражнение 4.5.

В языке Scheme есть дополнительная разновидность синтаксиса вариантов cond, ((проверка) => (потребитель)). Если результат вычисления (проверки) оказывается истинным значением, то вычисляется (потребитель). Его значение должно быть одноместной процедурой; эта процедура вызывается со значением (проверки) в качестве аргумента, и результат этого вызова возвращается как значение выражения cond. Например,

(cond ((assoc b ((a 1) (b 2))) => cadr)

(else false))

имеет значение 2. Измените обработку cond так, чтобы она поддерживала этот расширенный синтаксис.


Упражнение 4.6.

Выражения let производны, поскольку

(let (((пер1)(выр1)) ... ((перп){вырп))) (тело))

эквивалентно

((lambda ((пер1) ... (перп)) ( тело ) )

(выр1) ( вырп ) )

Напишите синтаксическое преобразование let->combination, которое сводит вычисление let-выражений к вычислению комбинаций указанного вида, и добавьте соответствующую ветку для обработки let к eval.

Упражнение 4.7.

Особая форма let* подобна let, но только связывания переменных в let* происходят последовательно, и каждое следующее связывание происходит в окружении, где видны все предыдущие. Например,

(let* ((x 3)

(У (+ x 2)) (z (+ x y 5))) (* x z))

возвращает значение 39. Объясните, каким образом можно переписать выражение let* в виде набора вложенных выражений let, и напишите процедуру let*->nested-lets, которая проделывает это преобразование. Если мы уже реализовали let (упражнение 4.6) и хотим теперь расширить интерпретатор так, чтобы он обрабатывал let*, достаточно ли будет добавить в eval ветвь, в которой действием записано

(eval (let*->nested-lets exp) env)

или нужно явным образом преобразовывать let* в набор непроизводных выражений? Упражнение 4.8.

«Именованный let» - это вариант let, который имеет вид (let (переменная) (связывание) (тело))

(Связывание) и (тело) такие же, как и в обычном let, но только (переменная) связана в (теле) с процедурой, у которой тело (тело), а имена параметров - переменные в (связываниях). Таким образом, можно неоднократно выполнять (тело), вызывая процедуру по имени (переменная). Например, итеративную процедуру для порождения чисел Фибоначчи (раздел 1.2.2) можно переписать при помощи именованного let как

(define (fib n)

(let fib-iter ((a 1) (b 0)

(count n)) (if (= count 0)

b

(fib-iter (+ a b) a (- count 1)))))



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