27. Автоматизация лифта
Прежде чем закончить интерлюдию о компьютерах, я хочу описать еще одну группу полезных идей об исходном коде, комментариях и объектном коде, которые мы сумеем применить, чтобы лучше понять, как значение может храниться в мозге. Не стоит сразу браться за головоломку – для начала целесообразно подробнейшим образом изучить предельно простой пример и усвоить все понятия. (В сфере искусственного интеллекта эти примеры называются модельными задачами. Прежде чем браться за жуткую реальную задачу, стоит сначала решить модельную.) В связи с этим я предлагаю вам познакомиться с историей – выдуманной ради простоты, но в остальном вполне реалистичной – о том, как лифтеров заменили компьютерные чипы.
В моей молодости были лифтеры – люди, работа которых заключалась в том, чтобы весь день ездить на лифте вверх-вниз и останавливаться на нужных этажах для посадки и высадки пассажиров. Когда-то они крутили любопытную ручку, которую можно было поворачивать по часовой стрелке и против часовой стрелки, чтобы направлять лифт вверх или вниз, и им требовалась определенная сноровка, чтобы останавливать кабину на нужной высоте. При входе в лифт и при выходе из него людям часто приходилось подниматься или спускаться на небольшую ступеньку, и лифтеры всегда их об этом предупреждали. Существовал целый свод правил относительно того, что и когда говорить, на какие этажи подниматься в первую очередь, как открывать двери и так далее. На стажировке они заучивали эти правила и практиковались следовать им, пока это не входило у них в привычку. Сами правила разрабатывались годами, и в процессе в них постоянно вносились небольшие изменения и уточнения. Представим, что этот процесс остановился, когда был создан идеальный свод правил. Он чудесно работал. Любой, кто в точности следовал правилам, становился превосходным лифтером.
Теперь представим, что случилось, когда простая компьютерная программа сумела взять на себя все задачи лифтера. (На самом деле это происходило постепенно, по мере того как появлялись все новые автоматические механизмы, которые забирали у лифтеров все более сложные задачи, но мы представим, будто лифты перешли от человеческого контроля к полностью компьютерному одним махом.)
Допустим, производитель лифтов нанимает команду программистов и вручает им свод правил, которым руководствовались лифтеры: “Вот подробное описание необходимых нам функций; напишите компьютерную программу, которая будет следовать правилам из этой книги так же хорошо, как лучшие лифтеры, и мы будем довольны”. Изучая свод правил, программисты составляют список всех нужных действий и условий, при которых их следует и не следует предпринимать. В процессе они могут избавиться от некоторой небрежности свода правил. К примеру, если они встроят в лифт датчики, которые будут обеспечивать остановку лифта на нужной высоте, они смогут избавиться от цикла, требующего от лифтера сказать “Осторожно, ступенька”, но, возможно, оставят простую (записанную на пленку) фразу “Этаж N-й. Будьте осторожны при выходе из кабины”. Затем они пишут набросок программы, используя так называемый псевдокод – неформальный язык, нечто среднее между обычным человеческим языком и более требовательной системой исходного кода. Строка псевдокода может выглядеть примерно так: “если этаж вызова > текущего этажа, то ASCEND до этаж вызова = текущему этажу и STOP; OPENDOOR. WAIT…”.
Как только план написан на псевдокоде и выполняет необходимые условия, псевдокод можно перевести в исходный код, который представляет собой гораздо более строгую и структурированную систему команд, включая определение терминов – переменных, подпрограмм и так далее. Человеку по-прежнему несложно расшифровать исходный код – в конце концов, его пишут люди, – а следовательно, правила и условия свода правил в нем достаточно очевидны, если знать, куда смотреть. Расшифровке исходного кода способствуют две его характеристики: во-первых, по названиям переменных и команд обычно можно понять, за что они отвечают (callfloor [этаж вызова], weightsum [общая масса], TELLFLOOR [объявить номер этажа] и т. д.). Во-вторых, как мы видели в главе 24, программисты могут добавлять к своему исходному коду комментарии, заключенные в скобки объяснения, которые говорят читателям исходного кода, что имел в виду программист и что должны делать разные элементы программы. При создании программы целесообразно снабжать свой код комментариями, ведь забыть, зачем нужна конкретная строка кода, очень легко. Эти комментарии окажутся очень полезны, когда вы будете исправлять ошибки программирования.
Исходный код составляется согласно строгому синтаксису, где каждому элементу отводится свое место и не допускаются пунктуационные ошибки, поскольку он загружается в программу-компилятор, которая берет исходный код и транслирует его в последовательности элементарных операций (объектный код), подлежащих исполнению реальной (или виртуальной) машиной. Компилятор не может гадать, что программист имел в виду в той или иной строке исходного кода, поэтому исходный код должен точно говорить компилятору, какие команды исполнять, однако компилятор может выполнять эти задачи множеством разных способов и умеет выбирать наиболее эффективный способ, исходя из обстоятельств. Одни компиляторы работают лучше других: к примеру, если загрузить одну и ту же программу (в исходном коде) в два разных компилятора, объектный код, выданный одним компилятором, может исполняться гораздо быстрее, чем объектный код, выданный другим компилятором. Допустим, вы написали шахматную программу, загрузили ее исходный код в два разных компилятора и запустили две скомпилированных версии играть друг против друга на одном компьютере. Хотя обе версии будут “обдумывать одни и те же мысли в одном и том же порядке” (у них нет другого выбора – у них одинаковый исходный код), возможно, одна из них всегда будет выигрывать, просто потому что она обдумывает эти мысли быстрее, используя меньшее количество базовых машинных циклов, а следовательно, просчитывает за отведенное время большее количество ходов!
Вернемся к нашему лифту. Как только компилятор скомпилировал объектный код, этот код может быть исполнен (это исполняемый файл, обычно в расширении. exe) реальной (или виртуальной) машиной. Возможно, придется исправить ряд ошибок (вернуться к исходному коду, поправить его, снова скомпилировать программу и т. д.), но в итоге получится “законченный”продукт. Его можно будет “вшить”в ПЗУ на крошечный чип, содержащий универсальную машину – и неограниченное количество виртуальных машин в придачу к ней, – и установить его в лифт. Установка предполагает подключение всех преобразователей входящих сигналов, включая сигналы кнопок, вмонтированных в пол весов, измеряющих общую массу пассажиров, и других структурных элементов лифта, и привязки исходящих сигналов к исполнительным механизмам (которые управляют двигателями, открывающими и закрывающими двери, поднимающими и опускающими кабину, а также обновляют информацию на дисплеях и проигрывают записи). Тадам! Машина заменила настоящего человека – даже не метафорического гомункула. И машина следует тем же правилам, что и лифтер. Неужели? На самом деле нет. Она вроде как следует тем же правилам. Она занимает промежуточное положение между человеком, который запоминает – то есть в буквальном смысле моделирует в своей голове – правила, диктующие его поведение, чтобы снова и снова сверяться с ними, и планетами, которые “подчиняются” уравнениям, изящно описывающим их орбиты. Мы, люди, тоже часто занимаем промежуточное положение, когда усваиваем или доводим до автоматизма следование ряду четких правил, которые впоследствии можем отбросить и даже забыть (“жи” и “ши” пиши через “и”, “ча” и “ща” пиши через “а”). Порой мы также вроде как следуем правилам, которые еще не выведены окончательно, например некоторым правилам русской грамматики, по-прежнему сбивающим с толку лингвистов. Скажем, лингвисты сегодня тщетно пытаются написать учебник хорошего разговорного русского языка, в то время как любой десятилетний носитель русского каким-то образом умудряется установить и избавить от ошибок довольно хорошую версию объектного кода для своей РВМ!
Прежде чем пойти дальше, обратите внимание, что комментарии к исходному коду, помогающие программистам отслеживать назначение всех взаимосвязанных элементов программного обеспечения, не имеют аналогов в процессе создания аппаратного обеспечения, прошивки и программного обеспечения нашего мозга. Когда естественный отбор устанавливает в наш мозг различные функциональные структуры, они напоминают лишенный комментариев код: у них есть четкое назначение, но это назначение не объясняется никакими ярлыками. Впрочем, если бы они и были, мозг все равно был бы не в состоянии их понять. (Подробнее об этом в главе 40.) Без комментариев и объяснений остаются и изменения, происходящие в процессе развития и обучения. Подобно лингвистам, мы отчаянно бьемся в попытках провести обратное конструирование всех этих “правил” и “процедур”. Эта задача даже сложнее обратного конструирования объектного кода с целью восстановления исходного кода (не считая комментариев), но теоретически она выполнима.