Pull to refresh

Разработка web-приложений на языке Common Lisp (часть вторая)

Reading time 5 min
Views 4K
Данный обзор является небольшим путеводителем для тех, решился (или решается) доверить этому чудесному языку будущее своего стартапа. Несмотря на то, что основной акцент будет ставиться на web-разработке, я постараюсь осветить также и более общие темы, так или иначе связанные с Common Lisp. Материал почерпнут из собственного опыта разработки web-сервиса AlterMoby.

Вторая часть этого обзора будет посвящена базовому конфигурированию Lisp-среды. Будет описана установка простой Lisp-системы. Кроме того, вкратце рассмотрим систему управления зависимостями ASDF.
image

Прежде чем двигаться дальше, нам потребуется настроить простую Lisp-систему, необходимую для экспериментирования. Нижеприведённая инструкция по установке рассчитана на Debian Lenny, но, наверняка, будет работать во многих других дистрибутивах Linux (например, в Ubuntu).

Итак, для начала инсталлируем следующие пакеты: SBCL, Emacs и SLIME. SBCL – это компилятор Common Lisp, который мы обсуждали в первой части этого обзора. Emacs – текстовый редактор, в котором будем писать программный код. Я никогда не порекомендовал бы вам этот редактор, если бы не одно существенное обстоятельство. Именно для него написан SLIME, третий из вышеперечисленных пакетов. SLIME (Superior Lisp Interaction Mode for Emacs) – это клиент-серверная система для взаимодействия с Lisp. Клиентская часть, которая так и называется — SLIME, интегрируется с Emacs (являясь его модулем расширения). Серверная часть SLIME называется SWANK и непосредственно взаимодействует с Lisp. SLIME-клиент и SWANK связываются друг с другом посредством TCP, что даёт возможность удалённо управлять Lisp-системой.

После инсталляции этих трёх компонентов нужно познакомить их друг с другом. Для этого добавляем в конфигурационный файл ~/.emacs следующие строки:

(setq inferior-lisp-program "/usr/bin/sbcl") (require 'slime) (slime-setup)

Теперь мы можем смело запускать нашу Lisp-систему. Открываем Emacs, вводим M-x slime (новичкам в Emacs читать краткое руководство). Если всё прошло хорошо, то откроется REPL (Lisp-консоль). Введите что-то вроде (+ 1 1) для уверенности в том, что SBCL запущен и выполняет наши команды.

Slime позволяет вычислять текущие выражения, искать определения символов, форматировать код, делать контекстные подсказки и многое-многое другое. Удобство работы со SLIME становится неоспоримым в сравнении с работой голого SBCL в терминале. Позже, когда появится опыт работы с Emacs (для тех, у кого его не было ранее), можно будет тонко сконфигурировать интерфейс. Например, поменять цвет фона и текста, добавить поддержку юникода и прочее. Сейчас это не так важно, главное, что мы имеем простую Lisp-среду в которой уже можно работать.

Поскольку мы не можем написать всё с нуля, нам потребуются готовые сторонние библиотеки. Потому будет полезным разобраться со способом их дистрибуции. Большинство сторонних библиотек используют систему управления зависимостями ASDF, ставшую де-факто стандартом в мире Common Lisp. Нам не потребуется инсталлировать ASDF – она идёт в комплекте с SBCL.

Итак, что собой представляет ASDF? Эту систему можно сравнить с утилитой make в мире UNIX. Она отслеживает связи и зависимости между различными единицами кода (от единичного файла до большого фреймворка), координируя их компиляцию и загрузку. Большинство ASDF-совместимых библиотек имеют в корневой директории один asd-файл, описывающий программную систему (в терминологии ASDF). Любая сколько нибудь сложная система состоит из нескольких компонентов. Компонент может быть как модулем, т.е. контейнером для других компонентов, так и отдельным файлом. Компоненты зависят от других компонентов, а системы — от других систем. На основании этих и других данных ASDF определяет порядок компиляции и загрузки целевой системы.

Структура и связи системы описываются с помощью декларативного DSL (предметно ориентированного языка). Важнейшей частью этого DSL является директива defsystem. Приведу пример простого asd-файла:

(in-package :asdf)
(defsystem my-lib :name "my-lib" :version "0.1" :components (
   (:module "common" :components (
      (:file "common-file-1")
      (:file "common-file-2")
      (:file "common-file-3" :depends-on ("common-file-1" "common-file-2"))))
   (:module "main" :components (
      (:file "main-file")) :depends-on (:common)))
   :depends-on (:my-base-lib))

Здесь первая строка содержит директиву переключения в пакет (аналог пространства имён в Common Lisp — здесь и далее слово «пакет» будет применяться в этом значении) ASDF. Это сделано для удобства, чтобы не мешать описание системы и код её реализации в одну кучу (в качестве альтернативы можно создать для этого новый пакет my-lib-asd). Далее определяется система my-lib, содержащая два модуля и зависящая от системы my-base-lib. Обычно каждый модуль соответствует директории с исходными файлами, объединёнными по некоторому структурному или функциональному признаку. В данном примере первый модуль называется “common” и содержит три файла: независимые “common-file-1” и “common-file-2” и зависимый от этих двух “common-file-3”. Второй модуль называется “main”, содержит единственный файл “main-file” и зависит от модуля “common”.

Чтобы загрузить систему “my-lib” нам потребуется ввести следующую команду:

(asdf:oos ‘asdf:load-op :my-lib)

Эта команда вначале проверит актуальность каждого из компонентов в каждой из систем (my-lib, my-base-lib и тех, от кого зависит последняя). Неактуальные компоненты будут перекомпилированы, актуальные – сразу загружены в память (т.е. их символы будут обработаны и добавлены в соответствующие пакеты). Если не все системы или компоненты, от которых зависит целевая система, будут найдены, то произойдёт ошибка загрузки.

Теперь разберёмся, откуда ASDF знает, где искать asd-файлы. При компиляции или загрузке системы ASDF просматривает список директорий, хранящийся в переменной asdf:*central-registry*, проверяя наличие требуемого asd-файла (его имя должно соответствовать имени целевой системы). Поэтому перед загрузкой новой системы можно добавить в этот список путь к её корневой директории. Более разумным подходом является выделение специальной директории, содержащей символьные ссылки на asd-файлы всех имеющихся систем. Для этой цели подойдёт директория /usr/share/common-lisp/systems/, путь к которой по умолчанию добавлен в asdf:*central-registry*.

Имея базовые знания о ASDF, мы уже можем пользоваться множеством сторонних библиотек, которые с избытком наличествуют в Интернете (здесь важнейшим путеводителем будет CLiki — крупнейший портал, посвящённый Common Lisp). Остаётся только один вопрос: как инсталлировать нужные библиотеки, автоматически отслеживая и скачивая их зависимости? ASDF располагает лишь базовой функциональностью, не позволяя автоматизировать процесс инсталляции. К счастью, есть достаточное количество ASDF-расширений, решающих эту задачу. К ним, в частности, можно отнести ASDF-INSTALL. Несмотря на эти расширения, я бы рекомендовал на первых порах ими не пользоваться и инсталлировать зависимости вручную. Это позволит хорошо понять внутренние связи в используемых библиотеках.
Tags:
Hubs:
+34
Comments 29
Comments Comments 29

Articles