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


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




[45]

Уровни языка помогают устойчивому проектированию

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

Нам удалось бросить взгляд и еще на одну существеннейшую идею касательно проектирования языков и программ. Это подход уровневого проектирования (stratified design), представление, что сложной системе нужно придавать структуру при помощи последовательности уровней, которая описывается последовательностью языков. Каждый из уровней строится путем комбинации частей, которые на этом уровне рассматриваются как элементарные, и части, которые строятся на каждом уровне, работают как элементарные на следующем уровне. Язык, который используется на каждом уровне такого проекта, включает примитивы, средства комбинирования и абстракции, соответствующие этому уровню подробности.

Уровневое проектирование пронизывает всю технику построения сложных систем. Например, при проектировании компьютеров резисторы и транзисторы сочетаются (и описываются при помощи языка аналоговых схем), и из них строятся и-, или- элементы и им подобные, служащие основой языка цифровых схем.31 Из этих элементов строятся процессоры, шины и системы памяти, которые в свою очередь служат элементами в построении компьютеров при помощи языков, подходящих для описания компьютерной архитектуры. Компьютеры, сочетаясь, дают распределенные системы, которые описываются при помощи языков описания сетевых взаимодействий, и так далее.

Как миниатюрный пример уровневого подхода, наш язык описания изображений использует элементарные объекты (элементарные рисовалки), создаваемые при помощи языка, в котором описываются точки и линии и создаются списки отрезков для рисовалки segments->painter либо градации серого цвета в рисовалке вроде rogers. Большей частью наше описание языка картинок было сосредоточено на комбинировании этих примитивов с помощью геометрических комбинаторов вроде beside и below. Работали мы и на более высоком уровне, где beside и below рассматривались как примитивы, манипу-лируемые языком, операции которого, такие как square-of-four, фиксируют стандартные схемы сочетания геометрических комбинаторов.

Уровневое проектирование помогает придать программам устойчивость (robustness), то есть повышает вероятность, что небольшое изменение в спецификации потребует относительно малых изменений в программе. Например, предположим, что нам нужно изменить картинку, основанную на рисовалке wave, которая показана на рисунке 2.9. Мы можем работать на самом низком уровне, изменяя конкретный вид элемента wave; можем работать на промежуточном уровне и менять то, как corner-split воспроизводит wave; можем на самом высоком уровне изменять то, как square-limit расставляет четыре копии по углам. В общем, каждый уровень такого проекта дает свой словарь для описания характеристик системы и свой тип возможных изменений.

31 Один из таких языков описывается в разделе 3.3.4.


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

Измените предел квадрата рисовалки wave, показанный на рисунке 2.9, работая на каждом из вышеописанных уровней. А именно:

a.Добавьте новые отрезки к элементарной рисовалке wave из упражнения 2.49 (например, изобразив улыбку).

b.Измените шаблон, который порождает corner-split (например, используя только одну копию образов up-split и right-split вместо двух).

c.Измените версию square-limit, использующую square-of-four, так, чтобы углы компоновались как-нибудь по-другому. (Например, можно сделать так, чтобы большой мистер Роджерс выглядывал из каждого угла квадрата.)

2.3 Символьные данные

Все составные объекты данных, которые мы до сих пор использовали, состояли, в конечном счете, из чисел. В этом разделе мы расширяем возможности представления нашего языка, разрешая использовать в качестве данных произвольные символы.

2.3.1 Кавычки

Раз теперь нам можно формировать составные данные, используя символы, мы можем пользоваться списками вроде

(a b c d)

(23 45 17)

((Norah 12) (Molly 9) (Anna 7) (Lauren 6) (Charlotte 3))

Списки, содержащие символы, могут выглядеть в точности как выражения нашего языка:

(* (+23 45) (+ x 9))

(define (fact n) (if (= n 1) 1 (* n (fact (- n 1)))))

Чтобы работать с символами, нам в языке нужен новый элемент: способность закавычить (quote) объект данных. Допустим, нам хочется построить список (a b) . Этого нельзя добиться через (list a b) , поскольку это выражение строит список из значений символов a и b, а не из них самих. Этот вопрос хорошо изучен по отношению к естественным языкам, где слова и предложения могут рассматриваться либо как семантические единицы, либо как строки символов (синтаксические единицы). В естественных языках обычно используют кавычки, чтобы обозначить, что слово или предложение нужно рассматривать буквально как строку символов. Например, первая буква «Джона» - разумеется, «Д». Если мы говорим кому-то «скажите, как Вас зовут», мы ожидаем услышать имя этого человека. Если же мы говорим кому-то «скажите "как Вас зовут"», то мы ожидаем услышать слова «как Вас зовут». Заметьте, как, для того, чтобы описать, что должен сказать кто-то другой, нам пришлось

32

использовать кавычки.32

32Когда мы разрешаем в языке кавычки, это разрушает нашу способность говорить о языке в простых терминах, поскольку становится неверным, что равнозначные выражения можно подстав-


Чтобы обозначать списки и символы, с которыми нужно обращаться как с объектами данных, а не как с выражениями, которые нужно вычислить, мы можем следовать тому же обычаю. Однако наш формат кавычек отличается от принятого в естественных языках тем, что мы ставим знак кавычки (по традиции, это символ одинарной кавычки ) только в начале того объекта, который надо закавычить. В Scheme это сходит нам с рук, поскольку для разделения объектов мы полагаемся на пробелы и скобки. Таким образом, значением одинарной кавычки является требование закавычить следующий объект.33

Теперь мы можем отличать символы от их значений:

(define a 1)

(define b 2)

(list a b) (1 2)

(list a b) (a b)

(list a b)

(a 2)

Кроме того, кавычки позволяют нам вводить составные объекты, используя обычное представление для печати списков:34

(car (a b c)) a

(cdr (a b c))

(b c)

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

лять друг вместо друга. Например, три есть два плюс один, но слово «три» не есть слова «два плюс один». Кавычки являются мощным инструментом, поскольку они дают нам способ строить выражения, которые работают с другими выражениями (как мы убедимся в главе 4, когда станем писать интерпретатор). Однако как только мы разрешаем в языке выражения, которые говорят о других выражениях того же языка, становится очень сложно соблюдать в каком-либо виде принцип «равное можно заменить равным». Например, если мы знаем, что утренняя и вечерняя звезда - одно и то же, то из утверждения «вечерняя звезда - это Венера» мы можем заключить, что «утренняя звезда - это Венера». Однако если нам дано, что «Джон знает, что вечерняя звезда - это Венера», мы не можем заключить, что «Джон знает, что утренняя звезда - это Венера».

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

34Строго говоря, то, как мы используем кавычку, нарушает общее правило, что все сложные выражения нашего языка должны отмечаться скобками и выглядеть как списки. Мы можем восстановить эту закономерность, введя особую форму quote, которая служит тем же целям, что и кавычка. Таким образом, мы можем печатать (quote a) вместо a и (quote (a b c)) вместо (a b c). Именно так и работает интерпретатор. Знак кавычки - это просто сокращение, означающее, что следующее выражение нужно завернуть в форму quote и получить (quote {выражение)). Это важно потому, что таким образом соблюдается принцип, что с любым выражением, которое видит интерпретатор, можно обращаться как с объектом данных. Например, можно получить выражение (car (a b c)) , и это будет то же самое, что и (car (quote (a b c))) , вычислив (list car (list quote (a b c))) .



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