Skip to content

Commit e036101

Browse files
committed
Chapter 1: section 3
1 parent 1db93ff commit e036101

File tree

4 files changed

+77
-73
lines changed

4 files changed

+77
-73
lines changed

.gitignore

-1
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,3 @@
77
*.pdf
88
*.toc
99
/epub/OEBPS/images/
10-
/book-src/compiled

book-src/.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*.html
2+
compiled/

book-src/ch01_basics/03_evaluating-atoms.poly.pm

+73-72
Original file line numberDiff line numberDiff line change
@@ -52,77 +52,74 @@
5252
◊indexR{переменные!связь с~символами}
5353
◊indexR{символы!связь с~переменными}
5454
Как видим, наш интерпретатор неявно преобразует символы в~переменные.
55-
Если быть более дотошным, тогда вместо ◊ic{(lookup exp env)} надо записать что-то вроде:
55+
Если быть более дотошным, то вместо ◊ic{(lookup exp env)} надо записать что-то вроде:
5656

5757
◊code:lisp{
5858
... (lookup (symbol->variable exp) env) ...
5959
}
6060

61-
◊; продолжать здесь:
62-
6361
◊indexR{приведение типов}
6462
◊indexR{объекты!второго класса}
65-
В~таком случае мы явно говорим,
66-
что символ~◊ic{exp}, чьим значением является имя переменной, должен быть превращён в~переменную.
63+
В~таком случае мы явно говорим, что символ~◊ic{exp}, чьим значением является имя переменной, должен быть преобразован в~переменную.
6764
Также это подчёркивает тот факт, что функция ◊ic{symbol->variable}
6865
◊footnote{Лично я не~люблю называть функции приведения типов ◊nobr{◊ic{◊ii{x}->◊ii{y}}},
6966
потому что так сложнее понимать цепочки преобразований.
70-
Запись ◊ic{(◊ii{y}"~>◊ii{z}(◊ii{x}"~>◊ii{y} ...))} не~так очевидна, как ◊ic{(◊ii{z}<"~◊ii{y}(◊ii{y}<"~◊ii{x} ...))}.
71-
Хотя, с~другой стороны, одиночная запись ◊ic{◊ii{z}<"~◊ii{y}} не~так легко читается, как ◊ic{◊ii{y}"~>◊ii{z}}.
67+
Запись ◊nobr{◊ic{(◊ii{y}->◊ii{z}(◊ii{x}->◊ii{y} ...))}} не~так очевидна, как ◊nobr{◊ic{(◊ii{z}<-◊ii{y}(◊ii{y}<-◊ii{x} ...))}}.
68+
Хотя, с~другой стороны, одиночная запись ◊nobr{◊ic{◊ii{z}<-◊ii{y}}} не~так легко читается, как ◊nobr{◊ic{◊ii{y}->◊ii{z}}}.
7269
Приходится~выбирать.}
73-
вовсе не~переводит ◊ic{exp} сам в~себя;
74-
она превращает синтаксическую сущность (символ) в~семантическую (переменную).
75-
В~действительности, переменные — это лишь воображаемые объекты, которым язык и программист дали какие-то имена,
76-
и которые ради удобства используются в~форме имён.
77-
Способ представления имён также выбран из соображений удобства, так как Лисп имеет базовый тип символов.
78-
В~данном случае
79-
◊ic{symbol->variable} ничего не~делает, хотя на самом деле могла бы применяться
80-
какая-нибудь другая форма записи имени переменной, например:
81-
строка, состоящая из знака доллара и имени переменной; в~этом случае, конечно~же, ◊ic{symbol->variable} будет сложнее.
82-
83-
Если бы переменные действительно были лишь воображаемыми, то ◊ic{lookup}
84-
не~знала~бы как обрабатывать свой первый аргумент, так как она ожидает нечто
85-
«материальное». Так что нам надо преобразовать переменную в~её программное
86-
представление, какой-нибудь уникальный ключ, по которому ◊ic{lookup} сможет
87-
отыскать переменную в~окружении. Так что ещё точнее было~бы записать:
70+
вовсе не~переводит символ~◊ic{exp} сам в~себя;
71+
наоборот, она превращает синтаксическую сущность (символ) — в~семантическую (переменную).
72+
Имена переменных существуют лишь в~языке программирования для удобства программиста;
73+
если переменную везде переименовать, то поведение программы не~изменится.
74+
Способ представления имён выбран из соображений удобства, так как Лисп имеет базовый тип символов.
75+
В~нашем случае ◊ic{symbol->variable} ничего не~делает,
76+
хотя в~других языках может применяться какая-нибудь другая форма записи имени переменной
77+
(например, строка, состоящая из знака доллара и имени переменной);
78+
в~таком случае, конечно~же, ◊ic{symbol->variable} будет несколько сложнее.
79+
80+
Если у~переменных на самом деле нет имён, то как~же ◊ic{lookup} будет их находить в~окружении?
81+
Вместо переменной как таковой следует использовать её программное представление,
82+
какой-нибудь уникальный ключ, по которому ◊ic{lookup} сможет отыскать переменную в~окружении.
83+
Так что ещё точнее было~бы записать:
8884

8985
◊code:lisp{
9086
... (lookup (variable->key (symbol->variable exp)) env) ...
9187
}
9288

93-
Однако, врождённая лень лисперов настаивает на использовании символов для
94-
ключей. Так что ◊ic{variable"~>key} — это лишь обратная функция
95-
к~◊ic{symbol◊discretionary{->}{}{->}variable}, и их последовательное применение
96-
никак не~изменяет~◊ic{exp}.
97-
98-
◊indexR{автоцитирование}◊indexR{механизм автоцитирования}
99-
Если выражение атомарное (то~есть не~является списком) и не~является символом,
100-
то соблазнительно его считать представлением какой-нибудь константы
101-
с~соответствующим значением. Такое поведение называется механизмом
102-
◊term{автоцитирования}. Автоцитируемый объект не~требует явного цитирования и
103-
имеет собственное значение. За примерами можно обратиться к~◊cite{cha96}.
104-
105-
Но является~ли такое поведение правильным? Во-первых, не~всегда атомарные
106-
объекты обозначают сами себя. Например, строка ◊ic{"a?b:c"} могла~бы означать
107-
вызов компилятора~Си, затем вызов получившейся программы и подстановку
108-
возвращаемого ей значения вместо этой строки.
109-
110-
С~другими объектами (вроде функций) вообще не~понятно, как именно их
111-
◊emph{вычислять}. К~примеру, ясно, что значением переменной ◊ic{car} является
112-
функция, возвращающая левый элемент пары, но что является значением самой
113-
функции ◊ii{car}? Чаще всего попытки вычисления значения функции считаются
114-
ошибочными.
115-
116-
◊indexC{()}◊indexR{пустой список, ◊protect◊ic{()}}
117-
Другой пример проблемного значения — пустой список~◊ic{()}. Судя по тому, что
118-
это список, он должен означать вызов функции. Вот только в~нём нет
119-
ни~аргументов, ни~самой функции. Такая запись в~Scheme запрещена и является
120-
синтаксической ошибкой.
121-
122-
Поэтому необходимо очень аккуратно анализировать программу и автоцитировать
123-
только те данные, для которых это явно стоить делать, например: числа, строки
124-
и~знаки. ◊seePage[basics/evaluating-forms/ssect:quoting] Так что мы записываем
125-
следующее:
89+
Однако, врождённая лень лисперов подсказывает, что в~качестве ключей можно использовать символы.
90+
Получается, что ◊ic{variable->key} — это лишь обратная функция к~◊ic{symbol->variable},
91+
а~их последовательное применение никак не~изменяет~◊ic{exp}.
92+
93+
◊indexR{автоцитирование}
94+
◊indexR{механизм автоцитирования}
95+
Если выражение атомарное (то~есть не~является списком) и~не~является символом,
96+
то соблазнительно его считать представлением константы с~соответствующим значением.
97+
Такое поведение называется механизмом ◊term{автоцитирования}.
98+
Автоцитируемый объект не~требует явного цитирования и имеет собственное значение.
99+
За~примерами можно обратиться к~◊cite{cha96}.
100+
101+
Но~является~ли такое поведение правильным?
102+
Во-первых, атомарные объекты не~всегда обозначают сами себя.
103+
Например, строка ◊ic{"a?b:c"} могла~бы означать вызов компилятора~Си,
104+
затем исполнение получившейся программы и подстановку возвращаемого ей значения вместо этой~строки.
105+
106+
С~другими объектами (вроде функций) вообще не~понятно, как именно их ◊emph{вычислять}.
107+
К~примеру, ясно, что значением переменной ◊ic{car} является функция, возвращающая левый элемент пары,
108+
но что является значением самой ◊emph{функции~◊ii{car}}?
109+
Чаще всего попытки вычисления значения функции считаются ошибочными.
110+
111+
◊indexC{()}
112+
◊indexR{пустой список, ◊ic{()}}
113+
Другой пример проблемного значения — пустой список~◊ic{()}.
114+
Судя по тому, что это список, он должен означать вызов функции.
115+
Вот только в~нём нет ни~аргументов, ни~самой функции.
116+
Такая запись в~Scheme запрещена и считается синтаксической ошибкой.
117+
118+
Поэтому необходимо очень аккуратно анализировать программу
119+
и автоцитировать только те данные, для которых это явно стоит делать,
120+
вроде чисел, строк, знаков.
121+
◊seePage{basics/evaluating-forms/ssect:quoting}
122+
Так что мы записываем следующее:
126123

127124
◊code:lisp{
128125
(define (evaluate exp env)
@@ -138,20 +135,24 @@
138135
◊indexR{ошибки!варианты обработки}
139136
◊indexC{wrong}
140137
◊phantomlabel{basic/atoms/para:the-first-error}
141-
В~этом фрагменте кода виден первый случай, когда могут возникнуть ошибки.
142-
Большая часть лисп-систем имеет свои собственные механизмы обработки
143-
исключительных ситуаций, которые непросто сделать переносимыми. В~случае ошибки
144-
мы вызываем ◊ic{wrong}◊footnote{Заметьте, не~«функцию ◊ic{wrong}». Варианты её
145-
реализации подробнее рассматриваются в~разделе~ref{compilation/sect:exception}.}
146-
и передаём ей первым аргументом строку. В~строке находится текстовое описание
147-
ошибки, а следующие за ней аргументы несут дополнительную информацию о~том, что
148-
вызвало проблему. Системы с~зачаточным механизмом обработки ошибок обычно
149-
в~случае проблем выдают какие"~то непонятные надписи вроде ◊ic{"Bus error: core
150-
dumped"} и умирают. Другие останавливают текущие вычисления и возвращаются
151-
к~диалоговому режиму. А~третьи могут связывать с~вычисляемым выражением
152-
специальный обработчик исключений, который перехватит брошенный объект,
153-
описывающий ошибку, и будет уже по нему решать, что делать дальше.
154-
◊seePage[compilation/sect:exception] В~некоторых случаях даже реализуется
155-
подобие экспертной системы, которая анализирует ошибку, вызвавший её код и
156-
выдаёт пользователю варианты её исправления. В~общем, сложно сказать однозначно,
157-
что следует делать в~случае ошибки.
138+
В~исполняемой программе могут быть ошибки,
139+
которые интерпретатору надо как-то обрабатывать.
140+
Большинство лисп-систем имеет механизмы обработки исключительных ситуаций,
141+
но~у~каждой реализации они свои собственные и не~всегда переносимые между реализациями.
142+
В~случае ошибки мы будем вызывать ◊ic{wrong},
143+
◊footnote{Заметьте, не~«◊emph{функцию}~◊ic{wrong}».
144+
Варианты её реализации подробнее рассматриваются в~разделе~ref{compilation/sect:exception}.}
145+
передавая первым аргументом строку.
146+
В~строке находится текстовое описание ошибки,
147+
а~следующие аргументы несут дополнительную информацию о~том, что вызвало проблему.
148+
Системы с~зачаточным механизмом обработки ошибок
149+
в~случае проблем обычно выдают какие-то непонятные надписи вроде ◊ic{"Bus~error: core~dumped"} и~умирают.
150+
Другие останавливают текущую работу и возвращаются к~диалоговому режиму.
151+
А~третьи могут связывать с~вычисляемым выражением специальный обработчик исключений,
152+
который перехватит объект, описывающий ошибку, и~будет уже по нему решать, что делать дальше.
153+
◊seePage{compilation/sect:exception}
154+
В~некоторых случаях даже реализуется подобие экспертной системы,
155+
которая самостоятельно анализирует ошибку, вызвавший её код,
156+
и выдаёт пользователю возможные варианты исправления возникшей ситуации.
157+
Короче говоря, сложно сказать однозначно, что следует делать в~случае~ошибки,
158+
поэтому пока~что мы будем просто вызывать~◊ic{wrong}.

book-src/index.ptree

+2
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,6 @@
33
01_preface.poly
44
◊ch01_basics/00_intro.poly{
55
ch01_basics/01_evaluation.poly
6+
ch01_basics/02_basic-evaluator.poly
7+
ch01_basics/03_evaluating-atoms.poly
68
}

0 commit comments

Comments
 (0)