Регистрация | Войти
Lisp — программируемый язык программирования
Предыдущая Оглавление Следующая

2. Намылить, смыть, повторить: знакомство с REPL

В этой главе вы настроите среду программирования и напишете свои первые программы на Common Lisp. Мы воспользуемся лёгким в установке дистрибутивом Lisp in a Box, разработанным Matthew Danish и Mikel Evins, включающим в себя реализацию Common Lisp, мощным, прекрасно поддерживающим Lisp текстовым редактором Emacs, а также SLIME1) — средой разработки на Common Lisp, основанной на Emacs.

Этот набор предоставляет программисту современную среду разработки на Common Lisp, поддерживающую инкрементальный интерактивный стиль разработки, характерный для программирования на этом языке. Среда SLIME даёт дополнительное преимущество в виде унифицированного пользовательского интерфейса, не зависящего от выбранных вами операционной системы и реализации Common Lisp. В своей книге я буду ориентироваться на среду Lisp in a Box, но те, кто хочет изучить другие среды разработки, например, графические интегрированные среды разработки (IDE - Integrated Development Environment), предоставляемые некоторыми коммерческими поставщиками, или среды, основанные на других текстовых редакторах, не должны испытывать больших трудностей в понимании.2)

Выбор реализации Lisp

Первое, что вам предстоит сделать — выбрать реализацию Lisp. Это может показаться немного странным тем, кто раньше занимался программированием на таких языках как Perl, Python, Visual Basic (VB), C# или Java. Разница между Common Lisp и этими языками заключается в том, что Common Lisp определяется своим стандартом: не существует ни единственной его реализации, контролируемой "великодушным диктатором" (как в случае с Perl и Python), ни канонической реализации, контролируемой одной компанией (как в случае с VB, C# или Java). Любой желающий может создать свою реализацию на основе стандарта. Кроме того, изменения в стандарт должны вноситься в соответствии с процессом, контролируемым Американским Национальным Институтом Стандартов (ANSI). Этот процесс организован таким образом, что "случайные лица", такие, как частные поставщики программных решений, не могут вносить изменения в стандарт по своему усмотрению3). Таким образом, стандарт Common Lisp — это договор между поставщиком Common Lisp и использующими Common Lisp разработчиками; этот договор подразумевает, что, если вы пишете программу, использующую возможности языка так, как это описано в стандарте, вы можете рассчитывать, что эта программа запустится на любой совместимой реализации Common Lisp.

С другой стороны, стандарт может описывать не всё из того, что вам может понадобиться в ваших программах. Более того, на некоторые аспекты языка спецификация намеренно отсутствует, чтобы дать возможность поэкспериментировать с различными способами их реализации, если при разработке стандарта не было достигнуто договорённости о наилучшем способе. Как видите, каждая реализация предоставляет пользователям как входящие в стандарт возможности, так и возможности, выходящие за его пределы. В зависимости от того, программированием какого рода вы собираетесь заняться, вы можете выбрать реализацию Common Lisp, поддерживающую именно те дополнительные возможности, которые вам больше всего понадобятся. С другой стороны, если вы предоставите право другим разработчикам пользоваться вашим кодом на Lisp, например, разработанными вами библиотеками, вы, вероятно, захотите — конечно, в пределах возможного — писать переносимый код на Common Lisp. Для нужд написания кода, который должен быть переносимым, но, в тоже время, использовать возможности, не описанные в стандарте, Common Lisp предоставляет гибкий способ писать код, "зависящий" от возможностей текущей реализации. Вы увидите пример такого кода в главе 15, когда мы будем разрабатывать простую библиотеку, "сглаживающую" некоторые различия в обработке разными реализациями Lisp имён файлов.

Сейчас, однако, наиболее важная характеристика реализации — её способность работать в вашей любимой операционной системе. Сотрудники компании Franz, занимающейся разработкой Allegro Common Lisp, выпустили пробную версию своего продукта, предназначенного для использования с этой книгой, и выполняющегося на GNU/Linux, Windows и OS X. У читателей, предпочитающих реализации с открытым исходным кодом, есть несколько вариантов. SBCL4) - высококачественная открытая реализация, способная компилировать в машинный код и работать на множестве различных UNIX-систем, включая Linux и OS X. SBCL — "наследник" CMUCL5) — реализации Common Lisp, разработанной в университете Carnegie Mellon, и, как и CMUCL, является всеобщим достоянием (public domain, за исключением нескольких секций, покрываемых BSD-подобными (Berkley Software Distributions) лицензиями). CMUCL — тоже хороший выбор, однако SBCL, обычно, легче в установке и поддерживает 21-разрядный Unicode6). OpenMCL будет отличным выбором для пользователей OS X: эта реализация способна компилировать в машинный код, поддерживать работу с потоками, а также прекрасно интегрируется с инструментальными комплектами Carbon и Cocoa. Кроме перечисленных, существуют и другие свободные и коммерческие реализации. Если вы захотите получить больше информации, в главе 32 вы найдёте список ресурсов.

Весь код на Lisp, приведённый в этой книге, должен работать на любой совместимой реализации Common Lisp, если явно не указано обратное, и SLIME будет "сглаживать" некоторые различия между реализациями, предоставляя общий интерфейс для взаимодействия с Lisp. Сообщения интерпретатора, приведённые в этой книге, сгенерированы Allegro, запущенном на GNU/Linux. В некоторых случаях другие реализации Lisp могут генерировать сообщения, незначительно отличающиеся от приведённых.

Введение в Lisp in a Box

Lisp in a Box спроектирован с целью быть "дружелюбным" к лисперам-новичкам и предоставлять первоклассную среду разработки на Lisp с минимальными усилиями, и потому всё что вам нужно для работы - это взять соответствующий пакет для вашей операционной системы и выбранную вами реализацию Lisp с веб-сайта Lisp in a Box (см. главу 32) и далее следовать инструкциям по установке.

Так как Lisp in a Box использует Emacs в качестве текстового редактора, вы должны хоть немного уметь им пользоваться. Возможно, лучший способ начать работать с Emacs - это изучать его по встроенному учебнику (tutorial). Чтобы вызвать tutorial, выберете первый пункт меню Help – Emacs tutorial. Или же зажмите Ctrl и нажмите h, затем отпустите Ctrl и нажмите t. Большинство команд в Emacs доступно через комбинации клавиш, поэтому они будут встречаться довольно часто, и чтобы долго не описывать комбинации (например: "зажмите Ctrl и нажмите h, затем..."), в Emacs существует краткая форма записи комбинаций клавиш. Клавиши, которые должны быть нажаты вместе, пишутся вместе, разделяются тире и называются связками; связки разделяются пробелами. C обозначает Ctrl, а M - Meta (Alt). Например вызов tutorial будет выглядеть таким образом: C-h t.

Tutorial также описывает много других полезных команд Emacs и вызывающих их комбинаций клавиш. У Emacs также есть расширенная онлайн документация, для просмотра которой используется специальный браузер – Info. Чтобы её вызвать нажмите C-h i. У Info также есть своя справка, которую можно вызвать, нажав клавишу h, находясь в браузере Info. Emacs предоставляет ещё несколько способов получить справку – это все сочетания клавиш, начинающиеся с C-h – полный список по C-h ?. В этом списке есть две полезные вещи: C-h k "объяснит" комбинацию клавиш, а C-h w – команду.

Ещё одна важная часть терминологии (для тех, кто отказался от работы с tutorial) - это буфер. Во время работы в Emacs, каждый файл, который Вы редактируете, представлен в отдельном буфере. Только один буфер может быть "текущим" в любой момент времени. В текущий буфер поступает весь ввод – всё, что Вы печатаете и любые команды, которые вызываете. Буферы также используются для представления взаимодействия с программами (например с Common Lisp). Есть одна простая вещь, которую вы должны знать – "переключение буферов", означающее смену текущего буфера, так что Вы можете редактировать определённый файл или взаимодействовать с определённой программой. Команда switch-to-buffer, привязанная к комбинации клавиш C-x b, запрашивает имя буфера (в нижней части окна Emacs). Во время ввода имени буфера, Вы можете пользоваться автодополнением по клавише Tab, которое по начальным символам завершает имя буфера или выводит список возможных вариантов. Просто нажав ввод, Вы переключитесь в буфер "по-умолчанию" (таким же образом и обратно). Вы также можете переключать буферы, выбирая нужный пункт в меню Buffers.

В определенных контекстах для переключения на определенные буферы могут быть доступны другие комбинации клавиш. Например, при редактировании исходных файлов Lisp сочетание клавиш C-c C-z переключает на буфер, в котором вы взаимодействуете с Lisp.

Освободите свой разум: Интерактивное программирование

При запуске Lisp in a Box, вы должны увидеть приглашение, которое может выглядеть примерно так :

 CL-USER>

Это приглашение Lisp. Как и приглашение оболочки DOS или UNIX, приглашение Lisp — это место, куда вы можете печатать выражения, которые заставляют что-либо делать компьютер. Однако вместо того, чтобы считывать и выполнять строку команд оболочки, Lisp считывает Lisp выражения, вычисляет их согласно правилам Lisp и печатает результат. Потом он (Lisp) повторяет свои действия со следующим введенным вами выражением. Вот вам бесконечный цикл: считывания, вычисления, и печати(вывода на экран), поэтому он называется цикл-чтение-вычисление-печать (по-английски read-eval-print-loop), или сокращённо REPL . Этот процесс может также называться top-level, top-level listener, или Lisp listener.

Через окружение, предоставленное REPL'ом, вы можете определять и переопределять элементы программ такие как переменные, функции, классы и методы; вычислять выражения Lisp; загружать файлы, содержащие исходные тексты Lisp или скомпилированные программы; компилировать целые файлы или отдельные функции; входить в отладчик; пошагово выполнять программы; и проверять состояние отдельных объектов Lisp.

Все эти возможности встроены в язык, и доступны через функции, определённые в стандарте языка. Если вы захотите, вы можете построить достаточно приемлемую среду разработки только из REPL и текстового редактора, который знает как правильно форматировать код Lisp. Но для истинного опыта Lisp программирования вам необходима среда разработки типа SLIME, которая бы позволяла вам взаимодействовать с Lisp как посредством REPL, так и при редактировании исходных файлов. Например, вы ведь не захотите каждый раз копировать и вставлять куски кода из редактора в REPL или перезагружать весь файл только потому, что изменилось одно определение, ваше окружение должно позволять вам вычислять или компилировать как отдельные выражения так и целые файлы из вашего редактора7).

Эксперименты в REPL

Для знакомства с REPL, вам необходимо выражение Lisp, которое может быть прочитано, вычислено и выведено на экран. Простейшее выражение Lisp - это число. Если вы наберете 10 в приглашении Lisp и нажмете ВВОД, то сможете увидите что-то наподобие:

 CL-USER> 10
10

Первая 10 - это то, что вы набрали. Считыватель Lisp, R в REPL, считывает текст "10" и создаёт объект Lisp, представляющий число 10. Этот объект - самовычисляемый объект, это означает, что такой объект при передаче в вычислитель, E в REPL, вычисляется сам в себя. Это значение подаётся на устройство вывода REPL, которое напечатает объект "10" в отдельной строке. Хотя это и похоже на сизифов труд, можно получить что-то поинтереснее, если дать интерпретатору Lisp пищу для размышлений. Например, вы можете набрать (+ 2 3) в приглашении Lisp.

 CL-USER> (+ 2 3)
5

Все что в скобках - это список, в данном случае список из трех элементов: символ +, и числа 2 и 3. Lisp, в общем случае, вычисляет списки, считая первый элемент именем функции, а остальные - выражениями для вычисления и передачи в качестве аргументов этой функции. В нашем случае, символ + - название функции которая вычисляет сумму. 2 и 3 вычисляются сами в себя и передаются в функцию суммирования, которая возвращает 5. Значение 5 отправляется на устройство вывода, которое отображает его. Lisp может вычислять выражения и другими способами, но не будем сильно отдаляться от основной темы. FIXME В первую очередь вы должны написать . . .

"Здравствуй, Мир" в стиле Lisp

Нет законченной книги по программированию без программы "Здравствуй, мир"("hello, world.")8). После того как интерпретатор запущен, нет ничего проще чем набрать строку "Здравствуй, мир".

 CL-USER> "Здравствуй, мир"
"Здравствуй, мир"

Это работает, поскольку строки, также как и числа, имеют символьный синтаксис, понимаемый считывателем Lisp, и являются самовычисляемыми объектами: Lisp считывает строку в двойных кавычках и создает в памяти строковой объект, который при вычислении вычисляется сам в себя и потом печатается в том же символьном представлении. Кавычки не являются частью строкового объекта в памяти - это просто синтаксис, который позволяет считывателю определить, что этот объект - строка. Устройство вывода REPL напечатает кавычки тоже, потому что оно пытается выводить объекты в таком же виде, в каком понимает их считыватель.

Однако, наш пример не может квалифицироваться как программа "Здравствуй мир". Это, скорее, значение "Здравствуй мир".

Вы можете сделать шаг к настоящей программе, напечатав код, который, в качестве побочного эффекта, отправит на стандартный вывод строку "Здравствуй, мир". Common Lisp предоставляет несколько путей для вывода данных, но самый гибкий - это функция FORMAT. FORMAT получает переменное количество параметров, но только два из них обязательны: указание, куда осуществлять вывод, и строка для вывода. В следующей главе Вы увидите, как строка может содержать встроенные директивы, которые позволяют вставлять в строку последующие параметры функции (а-ля printf или строка % из Python). До тех пор, пока строка не содержит символа ~, она будет выводиться как есть. Если вы передадите t в качестве первого параметра, функция FORMAT направит отформатированную строку на стандартный вывод. Итак, выражение FORMAT для печати "Здравствуй, мир" выглядит примерно так:9)

 CL-USER> (format t "Здравствуй, мир")
Здравствуй, мир
NIL

Стоит заметить, что результатом выражения FORMAT является NIL в строке после вывода "Здравствуй, мир". Этот NIL является результатом вычисления выражения FORMAT, напечатанного REPL. (NIL – это Lisp-версия false и/или null. Подробнее об этом рассказывается в главе 4.) В отличие от других выражений, рассмотренных ранее, нас больше интересует побочный эффект выражения FORMAT (в данном случае, печать на стандартный вывод), чем возвращаемое им значение. Но каждое выражение в Lisp вычисляется в некоторый результат10).

Однако, до сих пор остается спорным, написали ли мы настоящую программу. Но вы ведь здесь. Вы видите восходящий стиль программирования, поддерживаемый REPL: вы можете экспериментировать с различными подходами и строить решения из уже протестированных частей. Теперь, когда у вас есть простое выражение, которое делает то, что вы хотите, нужно просто упаковать его в функцию. Функции являются одним из основных строительных материалов в Lisp и могут быть определены с помощью выражения DEFUN подобным образом:

 CL-USER> (defun hello-world () (format t "hello, world"))
HELLO-WORLD

Выражение hello-world, следующее за DEFUN, является именем функции. В главе 4 мы рассмотрим, какие именно символы могут использоваться в именах, но сейчас будет достаточно сказать, что многие символы, такие как <<-", недопустимые в именах в других языках можно использовать Common Lisp. Это стандартный стиль Lisp – "not to mention more in line with normal English typography" – формирование составных имен с помощью дефисов, как в hello-world, вместо использования знаков подчеркивания, как в hello_world, или использованием заглавных букв внутри имени, как helloWorld. Скобки () после имени отделяют список параметров, который в данном случае пуст, так как функция не принимает аргументов. Остальное - это тело функции.

В какой-то мере это выражение подобно всем другим, которые вы видели, всего лишь еще одно выражение для чтения, вычисления и печати, осуществляемых REPL. Возвращаемое значение в этом случае - это имя только что определенной функции11). Но, подобно выражению FORMAT, это выражение более интересно своими побочными эффектами, нежели возвращаемым значением. Однако, в отличие от выражения FORMAT, побочные эффекты невидимы: после вычисления этого выражения создается новая функция, не принимающая аргументов, с телом (format t "hello, world") и ей дается имя HELLO-WORLD.

Теперь, после определения функции, вы можете вызвать ее следующим образом:

 CL-USER> (hello-world)
hello, world
NIL

Вы можете видеть, что вывод в точности такой же, как при вычислении выражения FORMAT напрямую, включая значение NIL, напечатанное REPL. Функции в Common Lisp автоматически возвращают значение последнего вычисленного выражения.

Сохранение вашей работы

Вы могли бы утверждать, что это готовая программа "hello, world". Однако, остаётся одна проблема. Если вы выйдете из Lisp и перезапустите его, определение функции исчезнет. Написав такую изящную функцию, вы захотите сохранить вашу работу.

Это достаточно легко. Вы просто должны создать файл, в котором сохраните определение. В Emacs вы можете создать новый файл набрав C-x C-f, и затем, когда Emacs выведет подсказку, введите имя файла, который вы хотите создать. Не особо важно, где будет находиться этот файл. Обычно исходные файлы Common Lisp именуются с расширением .lisp, хотя некоторые люди предпочитают .cl.

Открыв файл, вы можете набирать определение функции, введённое ранее в области REPL. Обратите внимание, что после набора открывающей скобки и слова DEFUN, в нижней части окна Emacs SLIME подскажет вам предполагаемые аргументы. Точная форма зависит от используемой вами реализации Common Lisp, но вы вероятно увидите что-то вроде этого:

 (defun name varlist &rest body)

Сообщение будет исчезать, когда вы будете начинать печатать каждый новый элемент, и снова появляться после ввода пробела. При вводе определения в файл, вы можете захотеть разбить определение после списка параметров так, чтобы оно занимало две строки. Если вы нажмете Enter, а затем Tab, SLIME автоматически выровняет вторую строку соответствующим образом12):

(defun hello-world ()
  (format t "hello, world")
)

SLIME также поможет вам в согласовании скобок – как только вы наберете закрывающую скобку, SLIME подсветит соответствующую открывающую скобку. Или вы можете просто набрать C-c C-q для вызова команды slime-close-parens-at-point, которая вставит столько закрывающих скобок, сколько нужно для согласования со всем открытыми скобками.

Теперь вы можете отправить это определение в вашу среду Lisp несколькими способами. Самый простой - это набрать C-c C-c, когда курсор находится где-нибудь внутри или сразу после формы DEFUN, что вызовет команду slime-compile-defun, которая, в свою очередь, пошлет определение в Lisp для вычисления и компиляции. Для того, чтобы убедиться, что это работает, вы можете сделать несколько изменений в hello-world, перекомпилировать ее, а затем вернуться назад в REPL, используя C-c C-z или C-x b, и вызвать ее снова. Например, вы можете сделать эту функцию более грамматически правильной.

(defun hello-world ()
  (format t "Hello, world!")
)

Теперь перекомпилируем ее с помощью C-c C-c и перейдем в REPL, набрав C-c C-z, чтобы попробовать новую версию.

 CL-USER> (hello-world)
Hello, world!
NIL

Теперь вы возможно захотите сохранить файл, с которым работаете; находясь в буфере hello.lisp, наберите C-x C-s для вызова функции Emacs save-buffer.

Теперь, для того, чтобы попробовать перезагрузить эту функцию из файла с исходным кодом, вы должны выйти из Lisp и перезапустить его. Для выхода вы можете использовать клавишную комбинацию SLIME: находясь в REPL, наберите запятую. Внизу окна Emacs вам будет предложено ввести команду. Наберите quit (или sayoonara), а затем нажмите Enter. Произойдет выход из Lisp, а все окна, созданные SLIME (такие как буфер REPL), закроются13). Теперь перезапустите SLIME, набрав M-x slime.

Просто ради интереса, вы можете попробовать вызвать hello-world.

 CL-USER> (hello-world)

После этого возникнет новый буфер SLIME, содержимое которого будет начинаться с чего-то вроде этого:

attempt to call `HELLO-WORLD' which is an undefined function.
[Condition of type UNDEFINED-FUNCTION]
Restarts:
0: [TRY-AGAIN] Try calling HELLO-WORLD again.
1: [RETURN-VALUE] Return a value instead of calling HELLO-WORLD.
2: [USE-VALUE] Try calling a function other than HELLO-WORLD.
3: [STORE-VALUE] Setf the symbol-function of HELLO-WORLD and call it again.
4: [ABORT] Abort handling SLIME request.
5: [ABORT] Abort entirely from this process.
Backtrace:
0: (SWANK::DEBUG-IN-EMACS #<UNDEFINED-FUNCTION @ #x716b082a>)
1: ((FLET SWANK:SWANK-DEBUGGER-HOOK SWANK::DEBUG-IT))
2: (SWANK:SWANK-DEBUGGER-HOOK #<UNDEFINED-FUNCTION @ #x716b082a> #<Function SWANK-DEBUGGER-HOOK>)
3: (ERROR #<UNDEFINED-FUNCTION @ #x716b082a>)
4: (EVAL (HELLO-WORLD))
5: (SWANK::EVAL-REGION "(hello-world)
" T)

Что же произошло? Просто вы попытались вызвать функцию, которая не существует. Но не смотря на такое количество выведенной информации, Lisp на самом деле обрабатывает такую ситуацию изящно. В отличие от Java или Python, Common Lisp не просто генерирует исключение и разворачивает стек. И он точно не завершается, оставив после себя образ памяти (dump core), только потому, что вы попытались вызвать несуществующую функцию. Вместо этого он перенесет вас в отладчик.

Во время работы с отладчиком вы все еще имеете полный доступ к Lisp, поэтому вы можете вычислять выражения для исследования состояния вашей программы и может быть даже для исправления каких-то вещей. Сейчас не стоит беспокоиться об этом; просто наберите q для выхода из отладчика и возвращения назад в REPL. Буфер отладчика исчезнет, а REPL выведет следующее:

CL-USER> (hello-world) 
; Evaluation aborted
CL-USER>

Конечно, в отладчике можно сделать гораздо больше, чем просто выйти из него – в главе 19 мы увидим, например, как отладчик интегрируется с системой обработки ошибок. А сейчас, однако, важной вещью, которую нужно знать, является то, что вы всегда можете выйти из отладчика и вернуться обратно в REPL, набрав q.

Вернувшись в REPL вы можете попробовать снова. Ошибка произошла, потому что Lisp не знает определения hello-world. Поэтому вам нужно предоставить Lisp определение, сохраненное нами в файле hello.lisp. Вы можете сделать это несколькими способами. Вы можете переключиться назад в буфер, содержащий файл (наберите C-x b, а затем введите hello.lisp) и перекомпилировать определение, как вы это делали ранее с помощью C-c C-c. Или вы можете загрузить файл целиком (что будет более удобным способом, если файл содержит множество определений) путем использования функции LOAD в REPL следующим образом:

CL-USER> (load "hello.lisp")
; Loading /home/peter/my-lisp-programs/hello.lisp
T

T означает, что загрузка всех определений произошла успешно14). Загрузка файла с помощью LOAD в сущности эквивалентна набору каждого выражения этого файла в REPL в том порядке, в каком они находятся в файле, таким образом, после вызова LOAD, hello-world должен быть определен.

CL-USER> (hello-world)
Hello, world!
NIL

Еще один способ загрузки определений файла - предварительная компиляция файла с помощью COMPILE-FILE, а затем загрузка (с помощью LOAD) уже скомпилированного файла, называемого FASL-файлом, что является сокращением для fast-load file (быстро загружаемый файл). COMPILE-FILE возвращает имя FASL-файла, таким образом мы можем скомпилировать и загрузить файл из REPL следующим образом:

CL-USER> (load (compile-file "hello.lisp"))
;;; Compiling file hello.lisp
;;; Writing fasl file hello.fasl
;;; Fasl write complete
; Fast loading /home/peter/my-lisp-programs/hello.fasl
T

SLIME также предоставляет возможность загрузки и компиляции файлов без использования REPL. Когда вы находитесь в буфере с исходным кодом, вы можете использовать C-c C-l для загрузки файла с помощью slime-load-file. Emacs выведет запрос имени файла для загрузки с уже введенным именем текущего файла; вы можете просто нажать Enter. Или же вы можете набрать C-c C-k для компиляции и загрузки файла, представляемого текущим буфером. В некоторых реализациях Common Lisp компилирование кода таким образом выполнится немного быстрее; в других - нет, обычно потому что они всегда компилируют весь файл целиком.

Этого должно быть достаточно, чтобы дать вам почувствовать красоту того, как осуществляется программирование на Lisp. Конечно, я пока не описал всех трюков и техник, но вы увидели важнейшие элементы – взаимодействие с REPL, загрузку и тестирование нового кода, настройку и отладку. Серьезные хакеры Lisp часто держат образ Lisp непрерывно запущенным многие дни, добавляя, переопределяя и тестируя части своих программ инкрементально.

Кроме того, даже если приложение, написанное на Lisp, уже развернуто, часто существует возможность обратиться к REPL. В главе 26 вы увидите как можно использовать REPL и SLIME для взаимодействия с Lisp, запустившим Web-сервер, в то же самое время, когда он продолжает отдавать Web-страницы. Возможно даже использовать SLIME для соединения с Lisp, запущенным на другой машине, что позволяет, например, отлаживать удаленный сервер так же, как локальный.

И даже более впечатляющий пример удаленной отладки произошел в миссии NASA "Deep Space 1" в 1998 году. Через полгода после запуска космического корабля, небольшой код на Lisp должен был управлять космическим кораблем в течении двух дней для проведения серии экспериментов. Однако, неуловимое состояние гонки (race condition) в коде не было выявлено при тестировании на земле и было обнаружено уже в космосе. Когда ошибка была выявлена в космосе (100 миллионов миль от Земли) команда смогла произвести диагностику и исправление работающего кода, что позволило завершить эксперимент15). Один из программистов сказал об этом следующее:

Отладка программы, работающей на оборудовании стоимостью 100 миллионов долларов, которая находится в 100 миллионах миль от вас, является интересным опытом. REPL, работающий на космическом корабле, предоставляет бесценные возможности в нахождении и устранении проблем.

Вы пока не готовы отправлять какой бы то ни было код Lisp в дальний космос, но в следующей главе вы напишите программу, которая немного более интересна, чем "hello, world".

1)Superior Lisp Interaction Mode for Emacs
2)Если у вас уже был неудачный опыт работы с Emacs, то вы должны знать, что Lisp in a Box — IDE, имеющая в своём составе Emacs-подобный редактор и не требующая от вас отличного знания Emacs для программирования на Lisp. Однако с использованием текстового редактора, имеющего некоторую базовую поддержку Lisp, программировать будет на порядок приятнее. Наверняка вам захочется, чтобы редактор автоматически помечал парные скобки и сам мог расставить отступы в коде на Lisp. Так как Emacs почти целиком написан на одном из диалектов Lisp, Elisp, он имеет довольно хорошую поддержку редактирования такого кода. История Emacs неразрывно связана с историей Lisp и культурой Lisp-хакеров: первые версии Emacs, как и его непосредственные предшественники TECMACS и TMACS, были написаны заинтересованными в Lisp разработчиками в Массачусетском Технологическом Институте (MIT). Редакторами, использовавшимися на Lisp-машинах, были версии Emacs, целиком написанные на Lisp. Под влиянием любви хакеров к рекурсивным акронимам две первые реализации Emacs для Lisp-машин были названы EINE и ZWEI, что означало "EINE Is Not Emacs" и "ZWEI Was EINE Initially" соответственно. Некоторое время был распространён производный от ZWEI редактор, названный более прозаично, ZMACS.
3)На самом деле, существует очень малая вероятность пересмотра стандарта языка. Хотя существует некоторое количество недостатков, которые пользователи языка могут желать исправить, согласно процессу стандартизации ANSI существующий стандарт не подлежит открытию для внесения небольших изменений, и эти недостатки, на самом деле, не вызывают ни у кого серьёзных трудностей. Возможно, будущее стандартизации Common Lisp — за стандартами "де-факто", больше похожее на "стандартизацию" Perl и Python, когда различные разработчики экспериментируют с интерфейсами прикладного программирования (API) и библиотеками для реализации вещей, не описанных в стандарте языка, а другие разработчики могут принимать их; или заинтересованные программисты будут разрабатывать переносимые библиотеки для сглаживания различий между реализациями возможностей, не описанных в стандарте языка.
4)Steel Bank Common Lisp
5)CMU Common Lisp
6)SBCL стал "ответвлением" CMUCL, так как его разработчики хотели сосредоточиться на упорядочивании его внутренней организации и сделать его легче в сопровождении. "Ответвление" вышло очень удачным. Исправления ошибок привели к появлению серьёзных различий между двумя проектами, и, как теперь поговаривают, их снова планируют объединить.
7)Для использования русского языка необходима соотв. настройка Emacs, Slime(cvs-версия), и Вашего интерпретатора LISP. – прим. переводчика
8)Досточтимая фраза "hello, world" предшествует даже классической книге по языку C Кернигана и Ритчи, которая сыграла огромную роль в её популяризации. Первоначальный "hello, world" похоже пришёл из книги Брайана Кернигана "A Tutorial Introduction to the Language B", которая была частью Bell Laboratories Computing Science Technical Report #8: The Programming Language B, опубликованного в январе 1973 г. (Отчёт выложен в интернет http://cm.bell-labs.com/cm/cs/who/dmr/bintro.html.)
9)Есть несколько других выражений, которые тоже выводят строку "Здравствуй, мир"
10)На самом деле, как вы увидите, когда будет рассказано о возврате множественных значений, технически возможно написание выражений, которые не вычисляются ни в какие значения, но даже такие выражения рассматриваются как возвращающие NIL при вычислении в контексте, ожидающем возврата значения
11)В главе 4 будет рассказано, почему имя преобразуется в верхний регистр
12)Вы также можете ввести определение в двух строках в REPL, так как REPL читает выражение целиком, а не по строкам
13)клавишные комбинации SLIME – это не часть Common Lisp, это команды SLIME
14)Если по каким-то причинам LOAD не выполнилась успешно, вы получите другую ошибку и будете перенаправлены в отладчик. Если это произошло, наиболее вероятной причиной может быть то, что Lisp не может найти файл, возможно из-за того, что его текущая директория не совпадает с той, в которой находится файл. В этом случае вы можете выйти из отладчика, набрав q, а затем использовать клавиатурную комбинацию SLIME cd для изменения текущей директории – наберите запятую, а затем на приглашние к вводу команды – cd и имя директории, где был сохранен hello.lisp
15)http://www.flownet.com/gat/jpl-lisp.html
Предыдущая Оглавление Следующая
@2009-2013 lisper.ru