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


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




[112]

Измените преобразование let->combination из упражнения 4.6 так, чтобы оно поддерживало именованный let.

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

Во многих языках имеются различные конструкции для построения циклов, например, do, for, while и until. В Scheme итеративные процессы можно выразить через обычные вызовы процедур, так что особые конструкции не дают никакого существенного выигрыша в вычислительной мощности. С другой стороны, часто они удобны. Придумайте какие-нибудь конструкции для итерации, дайте примеры их использования и покажите, как их реализовать в виде производных выражений.

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

При помощи абстракции данных мы смогли написать процедуру eval так, что она не зависит от конкретного синтаксиса интерпретируемого языка. Чтобы проиллюстрировать это свойство, разработайте новый синтаксис для Scheme, изменив процедуры из этого раздела и ничего не трогая в eval и apply.

4.1.3 Структуры данных интерпретатора

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

Проверка предикатов

В условных выражениях мы воспринимаем в качестве истины все, кроме специального ложного объекта false.

(define (true? x)

(not (eq? x false)))

(define (false? x) (eq? x false))

Представление процедур

Работая с примитивами, мы предполагаем, что у нас есть следующие процедуры:

•(apply-primitive-procedure (процедура) (аргументы))

применяет данную элементарную процедуру к значениям аргументов из списка (аргументы) и возвращает результат вызова.

•(primitive-procedure? (процедура)) проверяет, является ли (процедура) элементарной.

Эти механизмы работы с элементарными процедурами подробнее описаны в разделе 4.1.4.

Составная процедура строится из параметров, тела процедуры и окружения при помощи конструктора make-procedure:


(define (make-procedure parameters body env) (list procedure parameters body env))

(define (compound-procedure? p) (tagged-list? p procedure))

(define (procedure-parameters p) (cadr p))

(define (procedure-body p) (caddr p))

(define (procedure-environment p) (cadddr p))

Действия над окружениями

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

•(lookup-variable-value (переменная) (окружение)) возвращает значение, связанное с символом (переменная) в (окружении), либо сообщает об ошибке, если переменная не связана.

•(extend-environment (переменные) (значения) (исх-окр))

возвращает новое окружение, состоящее из нового кадра, в котором символы из списка (переменные) связаны с соответствующими элементами списка (значения), а объемлющим окружением является окружение (исх-окр).

•(define-variable! (переменная) (значение) (окружение)) добавляет к первому кадру (окружения) новое связывание, которое сопоставляет (переменной) (значение).

•(set-variable-value! (переменная) (значение) (окружение))

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

Чтобы реализовать все эти операции, мы представляем окружение в виде списка кадров. Объемлющее окружение живет в cdr этого списка. Пустое окружение - это просто пустой список.

(define (enclosing-environment env) (cdr env))

(define (first-frame env) (car env))

(define the-empty-environment ())

Каждый кадр в окружении представляется в виде пары списков: список переменных, связанных в кадре, и список значений.14

14 В нижеследующем коде кадры не являются настоящей абстракцией данных: set-variable-value! и define-variable! явным образом изменяют значения в кадре при помощи set-car!. Назначение процедур работы с кадрами - сделать код операций над окружениями простым для чтения.


(define (make-frame variables values) (cons variables values))

(define (frame-variables frame) (car frame)) (define (frame-values frame) (cdr frame))

(define (add-binding-to-frame! var val frame) (set-car! frame (cons var (car frame))) (set-cdr! frame (cons val (cdr frame))))

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

(define (extend-environment vars vals base-env) (if (= (length vars) (length vals))

(cons (make-frame vars vals) base-env) (if (< (length vars) (length vals))

(error "Получено слишком много аргументов" vars vals) (error "Получено слишком мало аргументов" vars vals))))

Чтобы найти переменную в окружении, мы просматриваем список переменных в первом кадре. Если находим нужную переменную, то возвращаем соответствующий элемент списка значений. Если мы не находим переменную в текущем кадре, то ищем в объемлющем окружении, и так далее. Если мы добираемся до пустого окружения, нужно сообщить об ошибке «неопределенная переменная».

(define (lookup-variable-value var env) (define (env-loop env) (define (scan vars vals) (cond ((null? vars)

(env-loop (enclosing-environment env))) ((eq? var (car vars))

(car vals)) (else (scan (cdr vars) (cdr vals))))) (if (eq? env the-empty-environment)

(error "Несвязанная переменная" var) (let ((frame (first-frame env))) (scan (frame-variables frame) (frame-values frame))))) (env-loop env))

Чтобы присвоить переменной новое значение в указанном окружении, мы ищем переменную, точно так же, как в lookup-variable-value, и изменяем соответствующее значение, когда его находим.

(define (set-variable-value! var val env) (define (env-loop env) (define (scan vars vals) (cond ((null? vars)

(env-loop (enclosing-environment env))) ((eq? var (car vars))



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