common-lispErste Schritte mit common-lisp

Bemerkungen

Dies ist eine einfache Hallo Weltfunktion in Common Lisp. Beispiele drucken den Text Hello, World! (ohne Anführungszeichen; gefolgt von einem Zeilenumbruch) zur Standardausgabe.

Common Lisp ist eine Programmiersprache, die weitgehend interaktiv mit einer als REPL bezeichneten Schnittstelle verwendet wird. Die REPL (Read Eval Print Loop) ermöglicht das Eingeben von Code, das Auswerten (Ausführen) und das sofortige Anzeigen der Ergebnisse. Die Eingabeaufforderung für die REPL (an welcher Stelle der einzugebende Code CL-USER> wird) wird durch CL-USER> angezeigt. Manchmal erscheint vor dem > etwas anderes als CL-USER , aber dies ist immer noch eine REPL.

Nach der Aufforderung folgt Code, normalerweise entweder ein einzelnes Wort (dh ein Variablenname) oder ein Formular (eine Liste von Wörtern / Formularen, die zwischen ( und ) ) (dh ein Funktionsaufruf oder eine Deklaration usw.) In der nächsten Zeile wird jede Ausgabe angezeigt, die das Programm druckt (oder nichts, wenn das Programm nichts druckt) und dann die durch Auswertung des Ausdrucks zurückgegebenen Werte. Normalerweise gibt ein Ausdruck einen Wert zurück, aber wenn er mehrere Werte zurückgibt, werden sie einmal pro Zeile angezeigt.

Versionen

Ausführung Veröffentlichungsdatum
Common Lisp 1984-01-01
ANSI Common Lisp 1994-01-01

Hallo Welt

Was folgt, ist ein Auszug aus einer REPL-Sitzung mit Common Lisp, in der ein "Hallo, Welt!" Funktion ist definiert und ausgeführt. Eine ausführlichere Beschreibung einer REPL finden Sie in den Anmerkungen unten auf dieser Seite.

CL-USER> (defun hello ()
           (format t "Hello, World!~%"))
HELLO
CL-USER> (hello)
Hello, World!
NIL
CL-USER> 

Dies definiert die "Funktion" der Nullargumente namens " hello , die die Zeichenfolge "Hello, World!" gefolgt von einem Zeilenumbruch zur Standardausgabe und NIL .

Um eine Funktion zu definieren, schreiben wir

(defun name (parameters...)
  code...)

In diesem Fall heißt die Funktion hello , nimmt keine Parameter auf und führt einen Funktionsaufruf aus. Der von einer Lisp-Funktion zurückgegebene Wert ist das letzte auszuführende Code-Bit in der Funktion. hello gibt also zurück, was (format t "Hello, World!~%") Zurückgegeben wird.

Um eine Funktion aufzurufen, schreibt man (function-name arguments...) wobei function-name der Name der Funktion ist und arguments... die (durch Leerzeichen getrennte) Liste von Argumenten für den Aufruf. Es gibt einige Sonderfälle, die wie Funktionsaufrufe aussehen, aber im obigen Code nicht defun Es gibt keine defun Funktion, die aufgerufen wird. Sie wird speziell behandelt und definiert stattdessen eine Funktion.

An der zweiten Aufforderung der REPL, nachdem wir die hello Funktion definiert haben, rufen wir sie ohne Parameter auf, indem wir schreiben (hello) . Dies ruft die format mit den Parametern t und "Hello, World!~%" . Die format erzeugt eine formatierte Ausgabe basierend auf den angegebenen Argumenten (ein bisschen wie eine erweiterte Version von printf in C). Das erste Argument gibt an, wohin die Ausgabe erfolgen soll, wobei t Standardausgabe bedeutet. Das zweite Argument gibt an, was gedruckt werden soll (und wie zusätzliche Parameter zu interpretieren sind). Die Direktive (spezieller Code im zweiten Argument) ~% weist format an, einen Zeilenumbruch zu drucken (dh unter UNIX könnte es \n und unter Windows \r\n schreiben). Format gibt normalerweise NIL (ein bisschen wie NULL in anderen Sprachen).

Nach der zweiten Aufforderung sehen wir, dass Hello, World gedruckt wurde und in der nächsten Zeile war der zurückgegebene Wert NIL .

Hallo, Name

Dies ist ein etwas fortgeschritteneres Beispiel, das einige weitere Funktionen von allgemeinem Lisp zeigt. Wir beginnen mit einem einfachen Hello, World! Funktion und Demonstration der interaktiven Entwicklung an der REPL. Beachten Sie, dass jeder Text aus einem Semikolon ; an den Rest der Zeile ist ein Kommentar.

CL-USER> (defun hello ()
       (format t "Hello, World!~%")) ;We start as before
HELLO
CL-USER> (hello)
Hello, World!
NIL
CL-USER> (defun hello-name (name) ;A function to say hello to anyone
       (format t "Hello, ~a~%" name)) ;~a prints the next argument to format
HELLO-NAME
CL-USER> (hello-name "Jack")
Hello, Jack
NIL
CL-USER> (hello-name "jack") ;doesn't capitalise names
Hello, jack
NIL
CL-USER> (defun hello-name (name) ;format has a feature to convert to title case
       (format t "Hello, ~:(~a~)~%" name)) ;anything between ~:( and ~) gets it
WARNING: redefining COMMON-LISP-USER::HELLO-NAME in DEFUN
HELLO-NAME
CL-USER> (hello-name "jack")
Hello, Jack
NIL
CL-USER> (defun hello-name (name)
       (format t "Hello, ~:(~a~)!~%" name))
WARNING: redefining COMMON-LISP-USER::HELLO-NAME in DEFUN
HELLO-NAME
CL-USER> (hello-name "jack") ;now this works
Hello, Jack!
NIL
CL-USER> (defun hello (&optional (name "world")) ;we can take an optional argument
       (hello-name name)) ;name defaults to "world"
WARNING: redefining COMMON-LISP-USER::HELLO in DEFUN
HELLO
CL-USER> (hello)
Hello, World!
NIL
CL-USER> (hello "jack")
Hello, Jack!
NIL
CL-USER> (hello "john doe") ;note that this capitalises both names
Hello, John Doe!
NIL
CL-USER> (defun hello-person (name &key (number))
       (format t "Hello, ~a ~r" name number)) ;~r prints a number in English
HELLO-PERSON
CL-USER> (hello-person "Louis" :number 16) ;this doesn't quite work
Hello, Louis sixteen
NIL
CL-USER> (defun hello-person (name &key (number))
       (format t "Hello, ~:(~a ~:r~)!" name number)) ;~:r prints an ordinal
WARNING: redefining COMMON-LISP-USER::HELLO-PERSON in DEFUN
HELLO-PERSON
CL-USER> (hello-person "Louis" :number 16)
Hello, Louis Sixteenth!
NIL
CL-USER> (defun hello-person (name &key (number))
       (format t "Hello, ~:(~a ~@r~)!" name number)) ;~@r prints Roman numerals
WARNING: redefining COMMON-LISP-USER::HELLO-PERSON in DEFUN
HELLO-PERSON
CL-USER> (hello-person "Louis" :number 16)
Hello, Louis Xvi!
NIL
CL-USER> (defun hello-person (name &key (number)) ;capitalisation was wrong
       (format t "Hello, ~:(~a~) ~:@r!" name number))
WARNING: redefining COMMON-LISP-USER::HELLO-PERSON in DEFUN
HELLO-PERSON
CL-USER> (hello-person "Louis" :number 16) ;thats better
Hello, Louis XVI!
NIL
CL-USER> (hello-person "Louis") ;we get an error because NIL is not a number
Hello, Louis ; Evaluation aborted on #<SB-FORMAT:FORMAT-ERROR {1006641AB3}>.
CL-USER> (defun say-person (name &key (number 1 number-p)
                                      (title nil) (roman-number t))
       (let ((number (if number-p
                 (typecase number
                   (integer
                (format nil (if roman-number " ~:@r" " ~:(~:r~)") number))
                   (otherwise
                (format nil " ~:(~a~)" number)))
                 "")) ; here we define a variable called number
         (title (if title 
                (format nil "~:(~a~) " title)
                ""))) ; and here one called title
         (format nil "~a~:(~a~)~a" title name number))) ;we use them here

SAY-PERSON
CL-USER> (say-person "John") ;some examples
"John"
CL-USER> (say-person "john doe")
"John Doe"
CL-USER> (say-person "john doe" :number "JR")
"John Doe Jr"
CL-USER> (say-person "john doe" :number "Junior")
"John Doe Junior"
CL-USER> (say-person "john doe" :number 1)
"John Doe I"
CL-USER> (say-person "john doe" :number 1 :roman-number nil) ;this is wrong
"John Doe First"
CL-USER> (defun say-person (name &key (number 1 number-p)
                                      (title nil) (roman-number t))
       (let ((number (if number-p
                 (typecase number
                   (integer
                (format nil (if roman-number " ~:@r" " the ~:(~:r~)") number))
                   (otherwise
                (format nil " ~:(~a~)" number)))
                 ""))
         (title (if title 
                (format nil "~:(~a~) " title)
                "")))
         (format nil "~a~:(~a~)~a" title name number)))
WARNING: redefining COMMON-LISP-USER::SAY-PERSON in DEFUN
SAY-PERSON
CL-USER> (say-person "john doe" :number 1 :roman-number nil) ;thats better
"John Doe the First"
CL-USER> (say-person "louis" :title "king" :number 16 :roman-number nil)
"King Louis the Sixteenth"
CL-USER> (say-person "louis" :title "king" :number 16 :roman-number t)
"King Louis XVI"
CL-USER> (defun hello (&optional (name "World") &rest arguments) ;now we will just
       (apply #'hello-name name arguments)) ;pass all arguments to hello-name
WARNING: redefining COMMON-LISP-USER::HELLO in DEFUN
HELLO
CL-USER> (defun hello-name (name &rest arguments) ;which will now just use
       (format t "Hello, ~a!" (apply #'say-person name arguments))) ;say-person
WARNING: redefining COMMON-LISP-USER::HELLO-NAME in DEFUN
HELLO-NAME
CL-USER> (hello "louis" :title "king" :number 16) ;this works now
Hello, King Louis XVI!
NIL
CL-USER>

Hier werden einige der erweiterten Funktionen der format von Common Lisp sowie einige optionale Parameter und Schlüsselwortargumente (z. B. :number ) hervorgehoben. Dies ist auch ein Beispiel für die interaktive Entwicklung einer REPL in Common Lisp.

Das einfache Hello World-Programm in REPL

Common Lisp REPL ist eine interaktive Umgebung. Jedes nach der Eingabeaufforderung geschriebene Formular wird ausgewertet und anschließend als Ergebnis der Auswertung gedruckt. Das einfachste mögliche "Hallo, Welt!" - Programm in Common Lisp ist:

CL-USER> "Hello, World!"
"Hello, World!"
CL-USER>

Was hier passiert, ist, dass ein String-Costant in die REPL eingegeben wird, ausgewertet wird und das Ergebnis gedruckt wird. Aus diesem Beispiel ist ersichtlich, dass Zeichenfolgen wie Zahlen, Sonderzeichen wie NIL und T und einige andere Literale sich selbst auswertende Formen darstellen.

Grundausdrücke

Versuchen wir einen grundlegenden Ausdruck in der REPL:

CL-USER> (+ 1 2 3)
6
CL-USER> (- 3 1 1)
1
CL-USER> (- 3)
-3
CL-USER> (+ 5.3 (- 3 2) (* 2 2))
10.3
CL-USER> (concatenate 'string "Hello, " "World!")
"Hello, World!"
CL-USER> 

Der Grundbaustein eines Common Lisp-Programms ist das Formular . In diesen Beispielen haben wir Funktionsformen , d. H. Als Liste geschriebene Ausdrücke, in denen das erste Element ein Operator (oder eine Funktion) und die übrigen Elemente die Operanden sind (dies wird als "Präfixnotation" oder "Polnische Notation" bezeichnet) ”). Das Schreiben von Formularen in der REPL bewirkt deren Auswertung. In den Beispielen können Sie einfache Ausdrücke sehen, deren Argumente konstante Zahlen, Strings und Symbole sind (im Fall von 'string , der Name eines Typs). Sie können auch sehen, dass arithmetische Operatoren eine beliebige Anzahl von Argumenten annehmen können.

Es ist wichtig zu beachten, dass Klammern ein wesentlicher Bestandteil der Syntax sind und nicht wie in anderen Programmiersprachen frei verwendet werden können. Zum Beispiel ist das Folgende ein Fehler:

(+ 5 ((+ 2 4)))
> Error: Car of ((+ 2 4)) is not a function name or lambda-expression. ...

In Common Lisp-Formularen können auch Daten, Symbole, Makroformulare, Sonderformen und Lambda-Formulare verwendet werden. Sie können geschrieben werden, um ausgewertet zu werden, null, einen oder mehrere Werte zurückzugeben, oder sie können als Eingabe in ein Makro eingegeben werden, das sie in andere Formen transformiert.

Summe der Liste der ganzen Zahlen

(defun sum-list-integers (list)
    (reduce '+ list))

; 10
(sum-list-integers '(1 2 3 4))

; 55
(sum-list-integers '(1 2 3 4 5 6 7 8 9 10))

Lambda-Ausdrücke und anonyme Funktionen

Eine anonyme Funktion kann ohne Namen über einen Lambda-Ausdruck definiert werden . Für die Definition dieser Funktionstypen wird anstelle des Schlüsselworts defun das Schlüsselwort lambda verwendet. Die folgenden Zeilen sind alle äquivalent und definieren anonyme Funktionen, die die Summe zweier Zahlen ausgeben:

(lambda (x y) (+ x y))
(function (lambda (x y) (+ x y)))
#'(lambda (x y) (+ x y))

Ihre Nützlichkeit macht sich beim Erstellen von Lambda-Formularen bemerkbar, z. B. bei einem Formular, bei dem das erste Element der Lambda-Ausdruck ist und die übrigen Elemente die Argumente der anonymen Funktion sind. Beispiele ( Online-Ausführung ):

(print ((lambda (x y) (+ x y)) 1 2)) ; >> 3

(print (mapcar (lambda (x y) (+ x y)) '(1 2 3) '(2 -5 0))) ; >> (3 -3 3)

Allgemeine Lisp-Lernressourcen

Online-Bücher

Dies sind Bücher, die online frei zugänglich sind.

Online-Referenzen

Offline-Bücher

Dies sind Bücher, die Sie wahrscheinlich kaufen oder aus einer Bibliothek ausleihen müssen.

Online-Communities

Bibliotheken

Vorgefertigte Lisp-Umgebungen

Dies sind Lisp-Bearbeitungsumgebungen, die einfach zu installieren sind und mit denen Sie beginnen können, da alles, was Sie benötigen, vorgepackt und vorkonfiguriert ist.

  • Portacle ist eine tragbare und plattformübergreifende Common Lisp-Umgebung. Es enthält einen leicht angepassten Emacs mit Slime, SBCL (eine beliebte Common Lisp-Implementierung), Quicklisp und Git. Es ist keine Installation erforderlich, daher ist dies eine sehr schnelle und einfache Möglichkeit, um loszulegen.
  • Lispbox ist eine IDE- (Emacs + SLIME), Common Lisp-Umgebung (Clozure Common Lisp) und Bibliotheksmanager (Quicklisp), die als Archive für Windows, Mac OSX und Linux vorinstalliert ist. Nachkomme von "Lisp in a Box", empfohlen im praktischen Buch "Lisp".
  • Nicht vorverpackt, aber SLIME verwandelt Emacs in eine Common Lisp IDE und verfügt über ein Benutzerhandbuch , das Ihnen den Einstieg erleichtert. Erfordert eine separate Common Lisp-Implementierung.

Gemeinsame Lisp-Implementierungen

In diesem Abschnitt werden einige gängige CL-Implementierungen und deren Handbücher aufgeführt. Wenn nicht anders angegeben, handelt es sich hierbei um freie Software-Implementierungen. Siehe auch die Cliki-Liste der freien Software-Common-Lisp-Implementierungen und die Wikipedia-Liste der kommerziellen Common-Lisp-Implementierungen .