
384
Глава 4. Метаязыковая абстракция
Это похоже на потоковую процедуру integers-starting-from, описанную в раз-
деле 3.5.2, но есть важное различие: потоковая процедура возвращает поток, который
представляет последовательность всех целых чисел, начиная с n, а процедура, написан-
ная через amb, выдает одно целое число
44
.
Мысля абстрактно, мы можем представить, что выполнение выражения amb застав-
ляет время разветвиться, и на каждой ветке оно продолжается с одни м из возможных
значений выбора. Мы говорим, что amb представляет собой точку недетерминистско-
го выбора (nondeterministic choice point). Если бы у нас была машина с достаточным
числом процессоров, которые можно было бы динамически выделять, то поиск можно
было бы реализовать напрямую. Выполнение происходило бы, как в последовательной
машине, пока не встретится выражение amb. В э то т момент выделялись и инициали-
зировались бы дополнительные процессоры, которые продолжали бы все параллельные
потоки выполнения, обусловленные выбором. Каждый процессор продолжал бы последо-
вательное выполнение одного из потоков, как если бы он был единственным, пока поток
не оборвется, потерпев неудачу, не разделится сам ил и не завершится
45
.
С другой стороны, если у нас есть машина, которая способна выполнять только
один процесс (или небольшое число параллельных процессов), альтернативы приходит-
ся рассматривать последовате льно. Можно представить себе интерпретатор, который в
каждой точке выбора произвольн ым образом выбирает, по какой ветке продолжить вы-
полнение. Однако случайный выбор может легко привести к неудачам. Можно было бы
запускать такой интерпретатор многократно, делая случайный выбор и надеясь, что в
конце концов мы получим тре буемое значение, но лучше проводить систематический
поиск (systematic search) среди всех возможных путей выполнения. Amb-интерпретатор,
который мы разработаем в этом разделе, реализует систематический поиск следующим
образом: когда интерпретатор встречает выражение amb, он сначала выбирает первый
вариант. Такой выбор может в дальнейшем привести к другим точкам выбора. В каждой
точке выбора интерпретатор сначала будет выбирать первый вариант. Если выбор при-
водит к неудаче, интерпретатор автомагически
46
возвращается (backtracks) к последней
точке выбора и пробует следующий вариант. Если в какой-то точке выбора варианты ис-
черпаны, интерпретатор возвращается к предыдущей точке выбора и продолжает оттуда.
Такой процесс реализует стратегию поиска, которую называют поиск в глубину (depth-
first search) или хронологический поиск с возвратом (chronological backtracking)
47
.
44
На самом деле, различие между произвольным выбором с возвратом единственного значения и возвратом
всех возможных значений выбора определяется в некоторой степени точкой зрения. С точки зрения того кода,
который использует значение, недетерминистский выбор возвращает одно значение. С точки зрения програм-
миста, проектирующего код, недетерминистский выбор потенциально возвращает все возможные значения, а
вычисление разветвляется, вследствие чего каждое значение исследуется отдельно.
45
Можно возразить, что этот механизм безнадежно неэффективен. Чтобы решить какую-нибудь просто сфор-
мулированную задачу таким образом, могут потребоваться миллионы процессоров, и б
´
ольшую часть времени
б
´
ольшая часть этих процессоров будет ничем не занята. Это возражение нужно воспринимать в контексте ис-
тории. Память раньше точно так же считалась дорогим ресурсом. В 1964 году мегабайт памяти стоил 400 000
долларов. Сейчас в каждом персональном компьютере имеется много мегабайтов памяти, и б
´
ольшую часть вре-
мени б
´
ольшая часть этой памяти не используется. Трудно недооценить стоимость электроники при массовом
производстве.
46
Автомагически: «Автоматически, но при этом таким способом, который говорящий почему-либо (обычно
либо из-за его сложности, либо уродливости, или даже тривиальности) не склонен объяснять». (Steele 1983;
Raymond 1993)
47
У встраивания стратегий автоматического поиска в языки программирования долгая и пестрая история.
Первые предположения, что недетерминистские алгоритмы можно изящно реализовать в языке программиро-