In Common Lisp kannst du „Kommentare“ schreiben, die vom Computer ignoriert werden. Einzeilige Kommentare beginnen mit einem oder mehreren Semikolons (;), und gelegentlich siehst du Folgendes:
(code...) ; => value
Dabei wird der Kommentar verwendet, um anzugeben, welchen Wert Common Lisp nach der Ausführung des Codes in dieser Zeile zurückgibt.
Es ist idiomatisch, ein einzelnes Semikolon für einen kurzen Kommentar am Ende einer Zeile zu verwenden, zwei für einen längeren Kommentar über einem Codeabschnitt, drei für einen langen Kommentar, der etwas wie eine Funktion beschreibt, und vier für einen Kommentar wie einen Header am Anfang einer Quelldatei.
Alle Objekte in Common Lisp sind entweder „Atome“ (einzelne, unteilbare Werte) oder „Conses“ (die von der Konstruktorfunktion „cons“ erzeugt werden).
Ein Cons besteht aus zwei Teilen: dem ersten Element und dem Rest der Elemente.
Aus historischen Gründen heißen diese beiden Teile car und cdr.
Wenn diese Conses als Code ausgewertet werden, repräsentiert das erste Element (car) die aufgerufene Funktion, während der Rest der Elemente
(cdr) die Argumente für diese Funktion darstellen:
(<function> <arg1> <arg2> ... <argN>)
; ^ car ^ | ^ cdr ^
Der gesamte Common-Lisp-Code besteht aus S-Ausdrücken (symbolischen Ausdrücken). Kurz nennt man sie Sexprs. Jeder Sexpr ist entweder ein Atom oder ein Cons. Wenn S-Ausdrücke ausgewertet werden, geben sie automatisch einen Wert zurück, der den Platz des Ausdrucks einnimmt. Wenn du deine eigenen Funktionen schreibst (mit defun), wird der letzte Wert innerhalb des Rumpfes der defun automatisch zurückgegeben:
;; Defining a new function
(defun gimme-foo () 'foo)
;; Calling the function as an S-Expression
(gimme-foo) ; => FOO
Symbole in Common Lisp sind besondere Werte, die auf andere Werte zeigen können oder, im Fall von Keywords, auf sich selbst. Wenn Symbole von Lisp ausgewertet werden, werden sie durch die Werte ersetzt, auf die sie zeigen:
foo ; => <whatever-foo-points-to>
:foo ; => :FOO
Beachte, dass Keywords durch einen führenden Doppelpunkt (:) gekennzeichnet werden.
Quoting, also das Setzen eines ' vor einen S-Ausdruck, weist Lisp an, diesen Ausdruck nicht auszuwerten.
Indem wir 'foo in unserem defun-Beispiel quotiert haben, haben wir verhindert, dass Lisp versucht, den Wert nachzuschlagen, auf den FOO zeigen sollte (und ihn nicht findet). Stattdessen wurde der Wert FOO selbst zurückgegeben.
Wenn FOO nirgendwo in unserem Programm definiert wurde:
foo ; => <ERROR! Lisp doesn't know what foo points to!>
'foo ; => FOO
Vorerst kannst du das einfach als eine Möglichkeit betrachten, Symbole aus einer Funktion zurückzugeben, aber wir werden auf Quoting zurückkommen und seine Auswirkungen in zukünftigen Konzeptübungen weiter erkunden.
Du! Ja, du, mutiger Lisper! Lenny, das Lisp-Alien, braucht deine Hilfe! Lenny will mit all den anderen Lisp-Aliens abhängen, aber ihre Eltern haben Lenny gesagt, dass Lenny nirgendwo hingeht, bis das Zimmer aufgeräumt ist.
Das Problem ist: Lenny kann den Boden kaum sehen! Lenny kann ihre Atome nicht von ihren Conses unterscheiden, ihre Symbole nicht von ihren Keywords, ihre cars nicht von ihren cdrs!
Kannst du Lenny helfen, dieses Chaos zu beseitigen? Vergiss nicht deine Klammern, du wirst sie brauchen!
Bevor Lenny loslegen kann, braucht Lenny eine Auffrischung, wie Symbole und Keywords aussehen. Es ist eine Weile her, seit Lenny das letzte Mal aufgeräumt hat... Hilf Lenny, indem du zwei Funktionen definierst: lennys-favorite-food, die zu einem Symbol ausgewertet wird, und lennys-secret-keyword, die zu einem Keyword ausgewertet wird. Zum Beispiel:
(lennys-favorite-food) ; => LASAGNA
(lennys-secret-keyword) ; => :ALIENS-ARE-REAL
Beachte, dass du jedes beliebige Symbol oder Keyword zurückgeben kannst (falls du kein Fan von Lasagne bist oder nicht an Aliens glaubst).
Sobald Lenny ihr Wissen über Symbole und Keywords aufgefrischt hat, geht es ans Aufräumen! Um all die S-Ausdrücke zu sortieren, die in ihrem Zimmer herumliegen, braucht Lenny Hilfe dabei, festzustellen, was ein Cons und was ein Atom ist. Du kannst helfen, indem du zwei Funktionen implementierst, is-an-atom-p und is-a-cons-p:
(is-an-atom-p 'one-thing) ; => T
(is-an-atom-p '(two things)) ; => NIL
(is-a-cons-p 'one-thing) ; => NIL
(is-a-cons-p '(two things)) ; => T
Für diesen Abschnitt gibt es eine Reihe eingebauter Lisp-Funktionen, die dir nützlich sein können. Außerdem kannst du vorerst T einfach als wahr und NIL als falsch betrachten.
Zum Schluss sind Lennys Conses zu sperrig, um sie ordentlich wegzuräumen, also müssen sie in kleinere Teile zerlegt werden. Kannst du helfen, indem du zwei weitere Funktionen definierst, um die Conses aufzuteilen (first-thing und rest-of-it)?
(first-thing '(first second third)) ; => FIRST
(rest-of-it '(first second third)) ; => (SECOND THIRD)
Auch hier können einige der eingebauten Funktionen von Common Lisp nützlich sein.
Melde dich bei Exercism an, um Common Lisp mit 27 Konzepte92 Übungen und echtem menschlichen Mentoring zu lernen und zu meistern, alles kostenlos.