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


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




[89]

(if (has-value? me)

(inform-about-value new-constraint)) done) (define (me request)

(cond ((eq? request has-value?)

(if informant true false)) ((eq? request value) value) ((eq? request set-value!) set-my-value) ((eq? request forget) forget-my-value) ((eq? request connect) connect)

(else (error "Неизвестная операция -- CONNECTOR" request))))

me))

Внутренняя процедура соединителя set-my-value зовется, когда поступает требование установить значение соединителя. Если у соединителя нет текущего значения, он его устанавливает и запоминает ограничение, которое потребовало установки значения, в переменной informant.32 Затем соединитель оповещает все связанные с ним ограничения, кроме того, которое потребовало установить значение. Это проделывается с помощью следующего итератора, который применяет указанную процедуру ко всем элементам списка, кроме одного.

(define (for-each-except exception procedure list) (define (loop items)

(cond ((null? items) done)

((eq? (car items) exception) (loop (cdr items))) (else (procedure (car items)) (loop (cdr items)))))

(loop list))

Если от соединителя требуют забыть значение, он запускает внутреннюю процедуру forget-my-value, которая первым делом убеждается, что запрос исходит от того же самого объекта, который значение установил. Если это так, соединитель оповещает связанные с ним ограничения о потере значения.

Внутренняя процедура connect добавляет указанное ограничение к списку ограничений, если его там еще нет. Затем, если у соединителя есть значение, он сообщает об этом ограничению.

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

(define (has-value? connector) (connector has-value?))

(define (get-value connector) (connector value))

(define (set-value! connector new-value informant) ((connector set-value!) new-value informant))

(define (forget-value! connector retractor)

32Setter может и не быть ограничением. В примере с температурой мы использовали символ user в качестве значения setter.


((connector forget) retractor))

(define (connect connector new-constraint) ((connector connect) new-constraint))

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

С помощью элементарных ограничений сумматор, умножитель и константа, определите процедуру averager (усреднитель), которая принимает три соединителя a, b и c, и обеспечивает условие, что значение c равно среднему арифметическому значений a и b.

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

Хьюго Дум хочет построить квадратор, блок-ограничение с двумя выводами, такое, что значение соединителя b на втором выводе всегда будет равно квадрату значения соединителя a на первом выводе. Он предлагает следующее простое устройство на основе умножителя:

(define (squarer a b) (multiplier a a b))

В такой идее есть существенная ошибка. Объясните ее. Упражнение 3.35.

Бен Битобор объясняет Хьюго, что один из способов избежать неприятностей в упражнении 3.34 - определить квадратор как новое элементарное ограничение. Заполните недостающие части в Беновой схеме процедуры, реализующей такое ограничение:

(define (squarer a b)

(define (process-new-value) (if (has-value? b)

(if (< (get-value b) 0)

(error "квадрат меньше 0 -- SQUARER" (get-value b)) (альтернатива!)) (альтернатива2))) (define (process-forget-value) (тело!)) (define (me request) (тело2)) (остаток определения) me)

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

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

(define a (make-connector)) (define b (make-connector)) (set-value! a 10 user)

В какой-то момент при вычислении set-value! будет выполнено следующее выражение из внутренней процедуры соединителя:

(for-each-except setter inform-about-value constraints)

Нарисуйте диаграмму, изображающую окружение, в котором выполняется указанное выражение.

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

Процедура celsius-fahrenheit-converter выглядит громоздко по сравнению со стилем определения в формате выражения:


(define (celsius-fahrenheit-converter x) (c+ (c* (c/ (cv 9) (cv 5))

x)

(cv 32))) (define C (make-connector))

(define F (celsius-fahrenheit-converter C))

Здесь c+, c* и т. п. - «ограничительные» версии арифметических операций. Например, c+ берет в виде аргументов два соединителя, и возвращает соединитель, который связан с ними ограничением-сумматором:

(define (c+ x y)

(let ((z (make-connector))) (adder x y z)

z))

Определите аналогичные процедуры для c-, c*, c/ и cv (константа), так, чтобы можно было определять составные ограничения, как в вышеприведенном примере.33

3.4 Параллелизм: время имеет значение

Мы убедились в мощности вычислительных объектов с внутренним состоянием в качестве инструмента моделирования. Однако, как было сказано в разделе 3.1.3, за эту мощность приходится платить потерей референциальной прозрачности, которая ведет в дебри вопросов об идентичности и изменении, и необходимостью замены подстановочной модели вычислений на более сложную модель с окружениями.

33Представление в виде выражений удобно, потому что при этом отпадает необходимость давать имена промежуточным выражениям в вычислении. Наша исходная формулировка языка ограничений громоздка по той же причине, по которой многие языки оказываются громоздкими при работе с составными данными. Например, если нам нужно вычислить произведение (а + b) • (c + d), где переменные представляют вектора, мы можем работать в «императивном» стиле, с процедурами, которые присваивают значения указанным векторным аргументам, но сами не возвращают вектора как значения:

(v-sum a b templ) (v-sum c d temp2) (v-prod templ temp2 answer)

С другой стороны, мы можем работать с выражениями, используя процедуры, которые возвращают вектора как значения, и таким образом избежать прямого упоминания tempi и temp2:

(define answer (v-prod (v-sum a b) (v-sum c d)))

Поскольку Лисп позволяет возвращать составные объекты как результаты процедур, мы можем преобразовать свой императивный язык ограничений в язык на основе выражений, как показано в этом упражнении. В языках, где средства работы с составными объектами бедны, как в Алголе, Бейсике и Паскале (если явно не использовать паскалевские переменные-указатели), обычно при решении таких задач программист ограничен императивным стилем. Поскольку формат выражений предпочтителен, можно спросить, есть ли причина строить систему императивно, как мы поступили в этом разделе. Одна из причин состоит в том, что язык ограничений, не ориентированный на выражения, дает нам возможность работать не только с объектами-соединителями, но и с объектами-ограничениями (например, значением, порождаемым процедурой adder). Это будет полезно, если мы захотим расширить систему новыми операциями, которые работают с ограничениями напрямую, а не только косвенным образом через операции над соединителями. Хотя реализовать работу с выражениями на основе императивной реализации просто, сделать обратное значительно труднее.



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