zurück zum Artikel

Quicklisp und mehr: Neues bei Common Lisp

Sprachen
Quicklisp und mehr: Neues bei Common Lisp

Die Familie der Programmiersprache Lisp ist mit Clojure erweitert und wieder etwas prominenter geworden. Doch auch für das Arbeiten mit dem Klassiker Common Lisp gab es mit der Bibliotheksverwaltung Quicklisp eine wesentliche Neuerung. Mit dem Gespann Quicklisp, Emacs, SLIME und Git steht eine leistungsfähige Entwicklungsumgebung für Common Lisp zur Verfügung.

Bei Common Lisp [1] handelt es sich um eine seit 1994 [2] standardisierte Sprache [3] aus der Lisp-Familie.(Urspünglich war LISP das Akronym für "LISt Processing". Heute schreibt man nur noch Lisp). Erste Bemühungen zur Standardisierung gab es bereits vor 1984. Im Gegensatz zu Programmiersprachen wie Python gibt es einige kompatible Implementierungen von Common Lisp, sowohl freie als auch kommerzielle – mit verschiedenen Stärken und zusätzlichen Eigenschaften. Eine kurze Übersicht liefert die iX [4], eine ausführliche [5] mit mehr als zehn Implementierungen und der Auflistung der Eigenschaften stammt von Daniel Weinreb.

Common Lisp hat ein großes Einsatzspektrum [6]. Dazu gehört nicht nur funktionale Programmierung, sondern die Sprache bietet auch die Unterstützung für zum Beispiel imperative oder objektorientierte Programmierung mit dem Common Lisp Object System (CLOS [7]). Ein Blick ins Common-Lisp-Wiki CLiki [8] auf die für den praktischen Einsatz empfohlenen Bibliotheken [9] lässt erahnen, dass sich Common Lisp nicht nur für die oft unterstellten ausschließlich akademischen, sondern auch für die meisten zeitgemäßen Aufgaben einsetzen lässt.

Durch die frühe Standardisierung umfasst der Standard einige Dinge nicht, die man vielleicht erwartet hätte, etwa Threads und reguläre Ausdrücke. Viele Implementierungen stellen Threads und reguläre Ausdrücke zur Verfügung, und es ist die Aufgabe von Bibliotheken, erweiterte Funktionen oder Kompatibilitätsschichten für die Implementierungen anzubieten. Mit der Bibliotheksverwaltung Quicklisp [10] hat sich seit 2010 dank Zach Beane die Situation für das Ökosystem um Common Lisp deutlich verbessert.

Eine heute viel verwendete Kombination für die praktische Arbeit mit Common Lisp besteht aus Emacs [11], SLIME [12], Quicklisp und Git [13]. Dabei dient der Emacs als Editor, SLIME verbindet die Common-Lisp-Instanz mit dem Editor, während Quicklisp und Git der Fremd- beziehungsweise eigenen Softwareverwaltung dienen. Hierbei ist SLIME auf den Emacs-Editor angewiesen, ansonsten sind diese Komponenten unabhängig voneinander und man kann sie je nach persönlicher Präferenz weglassen oder durch andere ersetzen. Ein Vorteil dieser Kombination ist, dass sie die dynamische Natur der Programmentwicklung mit Common Lisp wie Read-Eval-Print Loop (REPL [14]) und Reflexion [15] unterstützt.

Die Qual der Wahl

Vor der Beschäftigung mit der Entwicklungsumgebung steht die Wahl einer Lisp-Implementierung. Zwei häufig verwendete freie sind Steel Bank Common Lisp (SBCL [16]) und Clozure CL (CCL [17]). Die meisten Entwickler von Bibliotheken entwickeln oder testen zumindest mit dem SBCL-Compiler unter Linux, sodass dieser dort oder unter FreeBSD eine gute Wahl darstellt. Unter Windows bietet sich eher CCL an. Unter Mac OS X laufen sowohl SBCL als auch CCL, wobei letzteres zusätzlich eine integrierte Entwicklungsumgebung mitbringt.

LispWorks [18] stellt für Windows, Mac, Linux und FreeBSD eine Personal Edition [19] seiner kommerziellen Implementierung zum Download bereit. Diese bringt eine eigene grafische Benutzeroberfläche mit, sodass sich Common Lisp auch gut ohne die Installation von Emacs oder SLIME testen lässt.

Emacs, SLIME, ASDF

Unverzichtbares Gespann

Der Emacs steht für alle gängigen Betriebssysteme zur Verfügung. Für Linux, Mac oder FreeBSD kann er aus der Distribution heraus übersetzt oder als Paket installiert werden. Übersetzte Pakete für Windows [20] sind ebenfalls bereitgestellt.

SLIME, der "The Superior Lisp Interaction Mode for Emacs" lässt sich über CVS beziehen:

cvs -d :pserver:anonymous:anonymous@common-lisp.net:/project/
slime/cvsroot co slime

oder als CVS-Snapshot [21] herunterladen.

Nach der Installation sind Emacs und SLIME sowie SLIME und die Lisp-Implementierung jeweils miteinander bekannt zu machen. Dazu setzt man einige Variablen in der Emacs-Konfigurationsdatei. Diese lässt sich aus dem Emacs heraus laden:

C-x C-f ~/.emacs

(Sprich Ctrl-x gefolgt von Ctrl-f drücken, dann am erscheinenden Prompt ~/.emacs eingeben.) Dann ergänzt man sie um die folgenden anzupassenden Einträge.

;;; SLIME mit Emacs bekannt machen

;; Installationsort von SLIME, hier in ~/slime
(add-to-list 'load-path "/home/cpape/slime")
(add-to-list 'load-path "/home/cpape/slime/contrib")

;; Zeichensatz festlegen
(setq slime-net-coding-system 'utf-8-unix)

;; SLIME laden
(require 'slime)

;; nuetzliche Module von SLIME laden
(slime-setup '(slime-fancy))
(slime-setup '(slime-autodoc))

;; Link zur HyperSpec-Dokumentation
(setq common-lisp-hyperspec-root
"http://www.lispworks.com/documentation/HyperSpec/")

;;; die Lisp-Implementierung mit SLIME bekannt machen,
;;; hier CCL auf FreeBSD AMD64
(setq inferior-lisp-program "/home/cpape/ccl/fx86cl64 -I
/home/cpape/ccl/fx86cl64.image")

Ist die Konfigurationsdatei korrekt ergänzt, kann Common Lisp durch den Aufruf M-x slime starten. (Sprich Alt+x drücken, dann slime am Prompt eingeben.) Ab Emacs 24 ist SLIME auch über das eingebaute Paketsystem installierbar.

Neben der eigentlichen SLIME-Umgebung steht zusätzlich die HyperSpec-Dokumentation [22] zur Verfügung, eine Hypertext-Fassung des ANSI-Standards für Common Lisp. Befindet sich der Cursor im Emacs auf einem Common-Lisp-Symbol, wird durch die Tastenkombination C-c C-d d der entsprechende Eintrag in der HyperSpec im Webbrowser aufgerufen. Die Dokumentation lässt sich auch herunterladen und dann lokal nutzen. Dazu ist der Eintrag in der Emacs-Konfiguration anzupassen.

Eine hervorragende Einführung in Common Lisp gibt Peter Seibel in seinem bei apress erschienenen und online ebenfalls verfügbaren Buch "Practical Common Lisp [23]".

Softwareorganisation und Projektbeschreibung

Soll Software auf unterschiedlichen Rechnern, vielleicht sogar für verschiedene Betriebssysteme entwickelt werden, sollte man sich Gedanken über die Organisation des Quellcodes machen. Einfach ist es, den eigenen Quellcode sortiert nach Programmiersprachen unter ~/src/ zu speichern, etwa für Common Lisp und JavaScript in ~/src/lisp und ~/src/javascript/. Das hat den Vorteil, dass die eigenen Common-Lisp-Programme innerhalb eines Verzeichnisbaums liegen und sich leicht aus der REPL heraus laden und starten lassen.

Ist ein Projekt etwas umfangreicher, sollte früh eine Projektbeschreibung erstellt werden. Dazu dient die Another System Definition Facility (ASDF [24]). Sie ist Bestandteil der meisten Common-Lisp-Implementierungen und lässt sich auch über Quicklisp installieren.

Eine typische ASDF-Datei first-cl-steps.asd könnte so aussehen.

(asdf:defsystem :first-cl-steps
:serial t
:depends-on (:cl-ppcre)
:components ((:file :package)
(:file :first-cl-steps)))

Es wird zuerst eine externe Bibliothek CL-PPCRE [25] für reguläre Ausdrücke als Abhängigkeit definiert. Das eigentliche Projekt besteht aus zwei Quelldateien: package.lisp und first-cl-steps.lisp. Das serial
bedeutet, dass die Dateien in der Reihenfolge ihres Auftretens geladen werden sollen.

Geladen wird das Projekt dann mit

(asdf:oos 'asdf:load-op :first-cl-steps)

Einfacher, als sich das zu merken, ist es, das Projekt mit Quicklisp wie weiter unten beschrieben zu laden.

Damit ASDF die eigene Software tatsächlich findet und Abhängigkeiten auflösen kann, kann ASDF unter Linux oder BSD der Ort der eigenen Projekte bekannt gemacht werden. Dazu legt man im Verzeichnis

~/.config/common-lisp/source-registry.conf.d/

eine Datei mit frei wählbarem Dateinamen, hier asdf2.conf, mit folgendem anzupassenden Inhalt an:

(:tree "/home/cpape/src/lisp/")

Wird ein neues Projekt zur Laufzeit angelegt, ist gegebenenfalls der Befehl (asdf:initialize-source-registry) aufzurufen, um ASDF das neue Projekt vorzustellen.

Ausführlich wird ASDF in der Anleitung [26] beschrieben, unter anderem die Konfiguration unter Windows. In naher Zukunft wird wahrscheinlich der Übergang zu ASDF3 stattfinden.

Git ist weit verbreitet und wird an vielen Stellen beschrieben. Durch das Konzept der gleichberechtigten verteilten Repositorys wird das Arbeiten auf verschiedenen Systemen und Implementierungen unterstützt, auch wenn nur eine einzelne Person an einem Projekt arbeitet. Mit Magit [27] existiert eine umfangreiche Unterstützung für Git im Emacs, die sich ab Emacs 24 durch den eingebauten Paketmanager installieren lässt. Zusammengefasst kann man zu Git im Vergleich zu Konkurrenten sagen, dass sich Softwareversionsmanagement nun ähnlich leichtgewichtig anfühlt wie mit Quicklisp das Installieren von Bibliotheken im Vergleich zu früheren Versuchen.

Quicklisp

Die Zentrale zum Schluss

Mit Quicklisp existiert seit 2010 eine gut funktionierende Paketverwaltung für Common Lisp. Sie folgt früheren Versuchen wie ASDF-INSTALL, die damit obsolet wurden. (ASDF-INSTALL ist nicht zu verwechseln mit ASDF. Mit ASDF werden Systeme definiert, während ASDF-INSTALL zum Installieren von Systemen dient(e).) Ein manuelles Suchen und Installieren von Software ist nur noch selten nötig. Zurzeit bietet Quicklisp knapp 2200 ASDF-Systeme zum Installieren an; das entspricht etwa 700 verschiedenen Bibliotheken. Entwickelt und betrieben wird Quicklisp von Zach Beane, es erfolgen Updates fast regelmäßig zum Anfang eines jeden Monats. Die Informationen zu Änderungen, welche Pakete neu hinzugekommen, welche in neuer Version verfügbar sind sowie welche entfernt wurden, findet man im Quicklisp-Blog [28].

Um Quicklisp zu installieren [29], ist nur die Datei quicklisp.lisp herunterzuladen [30], zum Beispiel ins Heimatverzeichnis, und mit (load "~/quicklisp.lisp") zu starten. Daraufhin erfolgen Anweisungen zu Installation und Hilfe, wobei zum Einrichten nur einmalig (quicklisp-quickstart:install) aufzurufen ist. Ist Quicklisp erst einmal installiert, reicht nach dem Starten der Lisp-Implementierung der Aufruf

(load "~/quicklisp/setup.lisp")

Quicklisp verfügt über genug Informationen über die jeweils verwendete Implementierung, um sich selbst in die jeweilige Initialisierungsdatei zu installieren und so den letzten Aufruf zu sparen:

(ql:add-to-init-file)

Dann steht Quicklisp nach jedem Start von Common Lisp bereit. Jede Lisp-Implementierung hat ihre eigene Initialisierungsdatei, sodass der letzte Aufruf für jede Implementierung einmal erfolgen sollte. Wird die Personal Edition von LispWorks verwendet, muss der Aufruf von setup.lisp jedes Mal aufs Neue erfolgen, da die Initialisierungsdatei hier unbeachtet bleibt.

Nach der Installation von Quicklisp ist die Funktion für die tägliche Arbeit #'quickload. Mit ihr lassen sich sowohl die Fremdbibliotheken als auch die eigenen Projekte laden. Beispielsweise holen

(quickload :cl-ppcre)

oder

(quickload :first-cl-steps)

die Bibliothek CL-PPCRE beziehungsweise das eigene Projekt "first-cl-steps". Wird das eigene Projekt zuerst geladen, wird die Abhängigkeit CL-PPCRE gegebenenfalls automatisch zuerst heruntergeladen und installiert, anschließend das eigene Projekt gestartet. Es gibt für die eigene Software und die unter Quicklisp verfügbaren Bibliotheken also nur noch einen Anlaufpunkt.

Um Informationen über verfügbare Systeme zu bekommen, bieten sich die Funktionen #'ql:system-apropos und #'ql:system-list an. Während letzteres eine Liste aller installierbaren Systeme ausgibt, lässt sich mit ersterem gezielt in den Namen suchen. So gibt

(ql:system-apropos "xml")

eine Liste aller Systeme aus, die "xml" enthalten.

Quicklisp bietet drei Update-Funktionen. Zum einen #'ql:update-client zum Aktualisieren der Quicklisp-Software selbst, zum anderen die Funktionen #'ql:update-dist und #'ql:update-all-dists. Quicklisp organisiert die Bibliotheken in Distributionen; zurzeit ist das nur die Distribution "Quicklisp". Mit den beiden Aufrufen ql:update-client) und (ql:update-all-dists) werden also sowohl Quicklisp selbst als auch alle Pakete auf den neuesten Stand gebracht. Änderungen an den Paketen werden aufgelistet und sind einmal zu bestätigen.

Quicklisp speichert auch ältere Versionen der installierten Software. Tritt nach einem monatlichen Update ein Problem auf, lässt sich zu einem älteren Stand der Distribution zurückkehren [31]. Dabei wird jede über Quicklisp installierte Software auf diesen älteren Stand zurückgesetzt, damit die Abhängigkeiten erhalten bleiben.

Ist eine Software nicht über Quicklisp installierbar, lässt sie sich als lokales Projekt unter ~/quicklisp/local-projects/ einrichten und ist dann ebenfalls mit #'quickload aufrufbar. Lokale Projekte werden von Quicklisp bevorzugt aufgerufen. Wird also eine andere Version einer Bibliothek benötigt, kann sie zusätzlich als lokales Projekt installiert werden, ohne an Quicklisp Änderungen vornehmen zu müssen.

Informationen über installierbare Quicklisp-Pakete und Downloadzahlen gibt es seit kurzem auf Quickdocs [32] von Eitarow Fukamachi. Man findet eine Suchfunktion, die nicht nur im ASDF-Systemnamen, sondern auch die in der Paketdokumentation sucht. Es werden die README-Dateien und die Abhängigkeiten der Bibliotheken untereinander dargestellt sowie Links zu Quelle und Download bereitgestellt. Außerdem lässt sich die API der Bibliothek betrachten. Quickdocs wird jeweils kurz nach den monatlichen Updates von Quicklisp aktualisiert.

Neben Quicklisp und Quickdocs ist Quickproject [33] erwähnenswert, das ebenfalls von Zach Beane stammt und sich über Quicklisp installieren lässt. Mit ihm wird mit nur einem Funktionsaufruf ein Projektrumpf in einem Unterverzeichnis angelegt, der eine README-Datei sowie alle Dateien aus der ASDF oben enthält.

Mit (ql:quickload :quickproject) wird Quickproject geladen und mit

(quickproject:make-project #P"~/src/lisp/first-cl-steps"
:depends-on '(cl-ppcre))

automatisch ein Projekt wie oben angelegt.

Fazit

Insbesondere mit Quicklisp hat in den letzten Jahren eine Neuerung bei Common Lisp Einzug gehalten, die, obwohl immer noch als Beta-Version bezeichnet, zuverlässig seinen Dienst verrichtet. Das früher häufige manuelle Suchen von Bibliotheken in der richtigen Version entfällt nun fast vollständig. Die Einstiegshürde in die Common-Lisp-Programmierung sollte damit nun einiges niedriger liegen.

Die beschriebenen Komponenten zusammen ergeben eine umfangreiche Entwicklungsumgebung, sie lassen sich aber auch je nach Belieben entfernen oder austauschen. Nur Quicklisp sollte fester Bestandteil werden. (ane [34])

Christian Pape
ist Mathematiker und nach zuletzt vier Jahren Tätigkeit in der Klimafolgenforschung nun selbständiger Softwareentwickler. Er setzt Common Lisp seit 2006 in privaten und beruflichen Projekten ein.

Links & Literatur

URL dieses Artikels:
http://www.heise.de/-1965566

Links in diesem Artikel:
[1] http://de.wikipedia.org/wiki/Common_Lisp
[2] http://webstore.ansi.org/RecordDetail.aspx?sku=ANSI+INCITS+226-1994+%28R2004%29
[3] http://www.lispworks.com/documentation/HyperSpec/Front/
[4] http://www.heise.de/ix/artikel/Klammer-auf-1377200.html
[5] http://common-lisp.net/~dlw/LispSurvey.html
[6] https://www.heise.de/developer/artikel/Episode-28-Bedeutung-Einsatzszenarien-und-Perspektive-von-Lisp-1194789.html
[7] http://de.wikipedia.org/wiki/Common_Lisp_Object_System
[8] http://cliki.net
[9] http://www.cliki.net/Current%20recommended%20libraries
[10] http://www.quicklisp.org
[11] http://www.gnu.org/s/emacs/
[12] http://common-lisp.net/project/slime/
[13] http://git-scm.com/
[14] http://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop
[15] http://de.wikipedia.org/wiki/Reflexion_%28Programmierung%29
[16] http://www.sbcl.org
[17] http://ccl.clozure.com/
[18] http://www.lispworks.com
[19] http://www.lispworks.com/downloads/
[20] http://ftp.gnu.org/gnu/emacs/windows/
[21] http://common-lisp.net/project/slime/snapshots/slime-current.tgz
[22] http://www.lispworks.com/documentation/common-lisp.html
[23] http://www.gigamonkeys.com/book/
[24] http://common-lisp.net/project/asdf/
[25] http://www.weitz.de/cl-ppcre/
[26] http://common-lisp.net/project/asdf/asdf.html
[27] https://github.com/magit/magit
[28] http://blog.quicklisp.org/
[29] http://www.quicklisp.org/beta/
[30] http://beta.quicklisp.org/quicklisp.lisp
[31] http://blog.quicklisp.org/2011/08/going-back-in-dist-time.html
[32] http://quickdocs.org
[33] http://www.xach.com/lisp/quickproject/
[34] mailto:ane@heise.de
[35] http://articulate-lisp.com/
[36] http://www.reddit.com/r/lisp
[37] http://planet.lisp.org/