LISP - Kurzanleitung

John McCarthy erfand LISP 1958, kurz nach der Entwicklung von FORTRAN. Es wurde zuerst von Steve Russell auf einem IBM 704-Computer implementiert.

Es eignet sich besonders für Programme für künstliche Intelligenz, da es symbolische Informationen effektiv verarbeitet.

Common Lisp entstand in den 1980er und 1990er Jahren aus dem Versuch, die Arbeit mehrerer Implementierungsgruppen, die Nachfolger von Maclisp waren, wie ZetaLisp und NIL (New Implementation of Lisp) usw., zu vereinheitlichen.

Es dient als gemeinsame Sprache, die für eine bestimmte Implementierung leicht erweitert werden kann.

In Common LISP geschriebene Programme hängen nicht von maschinenspezifischen Merkmalen wie Wortlänge usw. ab.

Merkmale von Common LISP

  • Es ist maschinenunabhängig

  • Es verwendet iterative Entwurfsmethoden und einfache Erweiterbarkeit.

  • Es ermöglicht die dynamische Aktualisierung der Programme.

  • Es bietet Debugging auf hoher Ebene.

  • Es bietet erweiterte objektorientierte Programmierung.

  • Es bietet ein praktisches Makrosystem.

  • Es bietet weitreichende Datentypen wie Objekte, Strukturen, Listen, Vektoren, anpassbare Arrays, Hash-Tabellen und Symbole.

  • Es ist ausdrucksbasiert.

  • Es bietet ein objektorientiertes Zustandssystem.

  • Es bietet eine vollständige E / A-Bibliothek.

  • Es bietet umfangreiche Kontrollstrukturen.

In LISP integrierte Anwendungen

Große erfolgreiche Anwendungen in Lisp.

  • Emacs

  • G2

  • AutoCad

  • Igor Engraver

  • Yahoo Store

Einrichtung der lokalen Umgebung

Wenn Sie weiterhin bereit sind, Ihre Umgebung für die Programmiersprache Lisp einzurichten, benötigen Sie die folgenden zwei auf Ihrem Computer verfügbaren Softwareprogramme: (a) Texteditor und (b) Lisp Executer.

Texteditor

Dies wird verwendet, um Ihr Programm einzugeben. Beispiele für wenige Editoren sind Windows Notepad, OS Edit-Befehl, Brief, Epsilon, EMACS und vim oder vi.

Name und Version des Texteditors können auf verschiedenen Betriebssystemen variieren. Beispielsweise wird Notepad unter Windows verwendet, und vim oder vi können sowohl unter Windows als auch unter Linux oder UNIX verwendet werden.

Die Dateien, die Sie mit Ihrem Editor erstellen, werden als Quelldateien bezeichnet und enthalten Programmquellcode. Die Quelldateien für Lisp-Programme werden normalerweise mit der Erweiterung ".lisp".

Stellen Sie vor Beginn der Programmierung sicher, dass Sie über einen Texteditor verfügen und über genügend Erfahrung verfügen, um ein Computerprogramm zu schreiben, in einer Datei zu speichern und schließlich auszuführen.

Der Lisp Executer

Der in die Quelldatei geschriebene Quellcode ist die vom Menschen lesbare Quelle für Ihr Programm. Es muss "ausgeführt" werden, um in die Maschinensprache zu gelangen, damit Ihre CPU das Programm gemäß den gegebenen Anweisungen tatsächlich ausführen kann.

Diese Lisp-Programmiersprache wird verwendet, um Ihren Quellcode in das endgültige ausführbare Programm auszuführen. Ich gehe davon aus, dass Sie Grundkenntnisse über eine Programmiersprache haben.

CLISP ist der GNU Common LISP-Multi-Architektur-Compiler, der zum Einrichten von LISP in Windows verwendet wird. Die Windows-Version emuliert eine Unix-Umgebung mit MingW unter Windows. Das Installationsprogramm kümmert sich darum und fügt der Windows-PATH-Variablen automatisch Clisp hinzu.

Den neuesten CLISP für Windows erhalten Sie hier - https://sourceforge.net/projects/clisp/files/latest/download

Standardmäßig wird im Startmenü eine Verknüpfung für den zeilenweisen Interpreter erstellt.

Verwendung von CLISP

Während der Installation, clisp wird automatisch zu Ihrer PATH-Variablen hinzugefügt, wenn Sie die Option (EMPFOHLEN) auswählen. Dies bedeutet, dass Sie einfach ein neues Eingabeaufforderungsfenster öffnen und "clisp" eingeben können, um den Compiler aufzurufen.

Um eine * .lisp- oder * .lsp-Datei auszuführen, verwenden Sie einfach -

clisp hello.lisp

LISP-Ausdrücke werden als symbolische Ausdrücke oder S-Ausdrücke bezeichnet. Die S-Ausdrücke bestehen aus drei gültigen Objekten, Atomen, Listen und Zeichenfolgen.

Jeder S-Ausdruck ist ein gültiges Programm.

LISP-Programme werden entweder auf einem ausgeführt interpreter oder als compiled code.

Der Interpreter überprüft den Quellcode in einer wiederholten Schleife, die auch als Read-Evaluate-Print-Schleife (REPL) bezeichnet wird. Es liest den Programmcode, wertet ihn aus und druckt die vom Programm zurückgegebenen Werte.

Ein einfaches Programm

Schreiben wir einen S-Ausdruck, um die Summe der drei Zahlen 7, 9 und 11 zu ermitteln. Dazu können wir an der Interpreter-Eingabeaufforderung eingeben.

(+ 7 9 11)

LISP gibt das Ergebnis zurück -

27

Wenn Sie dasselbe Programm wie ein kompilierter Code ausführen möchten, erstellen Sie eine LISP-Quellcodedatei mit dem Namen myprog.lisp und geben Sie den folgenden Code ein.

(write (+ 7 9 11))

Wenn Sie auf die Schaltfläche Ausführen klicken oder Strg + E eingeben, führt LISP diese sofort aus und das zurückgegebene Ergebnis lautet:

27

LISP verwendet die Präfixnotation

Möglicherweise haben Sie bemerkt, dass LISP verwendet prefix notation.

Im obigen Programm fungiert das Symbol + als Funktionsname für den Summierungsprozess der Zahlen.

In der Präfixnotation werden Operatoren vor ihren Operanden geschrieben. Zum Beispiel der Ausdruck,

a * ( b + c ) / d

wird geschrieben als -

(/ (* a (+ b c) ) d)

Nehmen wir ein anderes Beispiel, schreiben wir Code für die Umrechnung der Fahrenheitstemperatur von 60 ° F in die Celsius-Skala -

Der mathematische Ausdruck für diese Konvertierung lautet -

(60 * 9 / 5) + 32

Erstellen Sie eine Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(write(+ (* (/ 9 5) 60) 32))

Wenn Sie auf die Schaltfläche Ausführen klicken oder Strg + E eingeben, führt LISP diese sofort aus und das zurückgegebene Ergebnis lautet−

140

Evaluierung von LISP-Programmen

Die Bewertung von LISP-Programmen besteht aus zwei Teilen:

  • Übersetzung von Programmtext in Lisp-Objekte durch ein Leseprogramm

  • Implementierung der Semantik der Sprache in Bezug auf diese Objekte durch ein Evaluatorprogramm

Der Bewertungsprozess umfasst die folgenden Schritte:

  • Der Leser übersetzt die Zeichenfolgen in LISP-Objekte oder s-expressions.

  • Der Evaluator definiert die Syntax von Lisp formsdie aus s-Ausdrücken aufgebaut sind. Diese zweite Bewertungsebene definiert eine Syntax, die bestimmt, welches-expressions sind LISP-Formulare.

  • Der Evaluator arbeitet als Funktion, die ein gültiges LISP-Formular als Argument verwendet und einen Wert zurückgibt. Dies ist der Grund, warum wir den LISP-Ausdruck in Klammern setzen, da wir den gesamten Ausdruck / das gesamte Formular als Argumente an den Evaluator senden.

Das 'Hallo Welt'-Programm

Das Erlernen einer neuen Programmiersprache beginnt erst, wenn Sie lernen, die ganze Welt in dieser Sprache zu begrüßen, richtig!

Erstellen Sie daher eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(write-line "Hello World")

(write-line "I am at 'Tutorials Point'! Learning LISP")

Wenn Sie auf die Schaltfläche Ausführen klicken oder Strg + E eingeben, führt LISP diese sofort aus und das zurückgegebene Ergebnis lautet:

Hello World

I am at 'Tutorials Point'! Learning LISP

Grundbausteine ​​in LISP

LISP-Programme bestehen aus drei Grundbausteinen:

  • atom
  • list
  • string

Ein atomist eine Zahl oder Zeichenfolge zusammenhängender Zeichen. Es enthält Zahlen und Sonderzeichen.

Es folgen Beispiele für einige gültige Atome -

hello-from-tutorials-point
name
123008907
*hello*
Block#221
abc123

EIN list ist eine Folge von Atomen und / oder anderen Listen in Klammern.

Es folgen Beispiele für einige gültige Listen -

( i am a list)
(a ( a b c) d e fgh)
(father tom ( susan bill joe))
(sun mon tue wed thur fri sat)
( )

EIN string ist eine Gruppe von Zeichen in doppelten Anführungszeichen.

Es folgen Beispiele für einige gültige Zeichenfolgen -

" I am a string"
"a ba c d efg #$%^&!"
"Please enter the following details :"
"Hello from 'Tutorials Point'! "

Kommentare hinzufügen

Das Semikolonsymbol (;) dient zur Angabe einer Kommentarzeile.

Zum Beispiel,

(write-line "Hello World") ; greet the world

; tell them your whereabouts

(write-line "I am at 'Tutorials Point'! Learning LISP")

Wenn Sie auf die Schaltfläche Ausführen klicken oder Strg + E eingeben, führt LISP diese sofort aus und das zurückgegebene Ergebnis lautet:

Hello World

I am at 'Tutorials Point'! Learning LISP

Einige bemerkenswerte Punkte, bevor Sie mit dem nächsten fortfahren

Im Folgenden sind einige wichtige Punkte aufgeführt, die zu beachten sind:

  • Die grundlegenden numerischen Operationen in LISP sind +, -, * und /

  • LISP repräsentiert einen Funktionsaufruf f (x) als (fx), zum Beispiel wird cos (45) als cos 45 geschrieben

  • LISP-Ausdrücke unterscheiden nicht zwischen Groß- und Kleinschreibung, cos 45 oder COS 45 sind gleich.

  • LISP versucht, alles zu bewerten, einschließlich der Argumente einer Funktion. Nur drei Arten von Elementen sind Konstanten und geben immer ihren eigenen Wert zurück

    • Numbers

    • Der Buchstabe t, das steht für logisch wahr.

    • Der Wert nil, das steht für logisch falsch sowie eine leere Liste.

Wenig mehr über LISP-Formulare

Im vorherigen Kapitel haben wir erwähnt, dass der Evaluierungsprozess des LISP-Codes die folgenden Schritte umfasst.

  • Der Leser übersetzt die Zeichenfolgen in LISP-Objekte oder s-expressions.

  • Der Evaluator definiert die Syntax von Lisp formsdie aus s-Ausdrücken aufgebaut sind. Diese zweite Auswertungsebene definiert eine Syntax, die bestimmt, welche S-Ausdrücke LISP-Formen sind.

Nun könnte ein LISP-Formular sein.

  • Ein Atom
  • Eine leere oder nicht Liste
  • Jede Liste, deren erstes Element ein Symbol enthält

Der Evaluator arbeitet als Funktion, die ein gültiges LISP-Formular als Argument verwendet und einen Wert zurückgibt. Dies ist der Grund, warum wir die setzenLISP expression in parenthesis, weil wir den gesamten Ausdruck / das gesamte Formular als Argumente an den Evaluator senden.

Namenskonventionen in LISP

Name oder Symbole können aus einer beliebigen Anzahl von anderen alphanumerischen Zeichen als Leerzeichen, offenen und schließenden Klammern, doppelten und einfachen Anführungszeichen, Backslash, Komma, Doppelpunkt, Semikolon und vertikalem Balken bestehen. Um diese Zeichen in einem Namen zu verwenden, müssen Sie das Escape-Zeichen (\) verwenden.

Ein Name kann Ziffern haben, aber nicht vollständig aus Ziffern bestehen, da er dann als Zahl gelesen wird. Ebenso kann ein Name Punkte haben, aber nicht vollständig aus Punkten bestehen.

Verwendung eines einfachen Anführungszeichens

LISP wertet alles aus, einschließlich der Funktionsargumente und Listenmitglieder.

Manchmal müssen wir Atome oder Listen wörtlich nehmen und wollen nicht, dass sie ausgewertet oder als Funktionsaufrufe behandelt werden.

Dazu müssen wir dem Atom oder der Liste ein einfaches Anführungszeichen voranstellen.

Das folgende Beispiel zeigt dies.

Erstellen Sie eine Datei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(write-line "single quote used, it inhibits evaluation")
(write '(* 2 3))
(write-line " ")
(write-line "single quote not used, so expression evaluated")
(write (* 2 3))

Wenn Sie auf die Schaltfläche Ausführen klicken oder Strg + E eingeben, führt LISP diese sofort aus und das zurückgegebene Ergebnis lautet:

single quote used, it inhibits evaluation
(* 2 3) 
single quote not used, so expression evaluated
6

In LISP werden Variablen nicht eingegeben, Datenobjekte jedoch.

LISP-Datentypen können als kategorisiert werden.

  • Scalar types - zum Beispiel Zahlentypen, Zeichen, Symbole usw.

  • Data structures - Zum Beispiel Listen, Vektoren, Bitvektoren und Strings.

Jede Variable kann jedes LISP-Objekt als Wert annehmen, es sei denn, Sie haben es explizit deklariert.

Es ist zwar nicht erforderlich, einen Datentyp für eine LISP-Variable anzugeben, dies hilft jedoch bei bestimmten Schleifenerweiterungen, bei Methodendeklarationen und einigen anderen Situationen, die in späteren Kapiteln erläutert werden.

Die Datentypen sind in einer Hierarchie angeordnet. Ein Datentyp ist eine Menge von LISP-Objekten, und viele Objekte können zu einer solchen Menge gehören.

Das typep Das Prädikat wird verwendet, um festzustellen, ob ein Objekt zu einem bestimmten Typ gehört.

Das type-of Funktion gibt den Datentyp eines bestimmten Objekts zurück.

Typspezifizierer in LISP

Typspezifizierer sind systemdefinierte Symbole für Datentypen.

Array Fixnum Paket einfache Zeichenfolge
Atom schweben Pfadname einfacher Vektor
Bignum Funktion Zufallszustand Single-Float
bisschen Hash-tabelle Verhältnis Standard-Char
Bitvektor ganze Zahl rational Strom
Charakter Stichwort lesbare Tabelle Zeichenfolge
[verbreitet] Liste Reihenfolge [string-char]
kompilierte Funktion Long-Float Short-Float Symbol
Komplex nill signiertes Byte t
Nachteile Null einfaches Array Byte ohne Vorzeichen
Doppelschwimmer Nummer einfacher Bitvektor Vektor

Neben diesen systemdefinierten Typen können Sie Ihre eigenen Datentypen erstellen. Wenn ein Strukturtyp mit definiert wirddefstruct Funktion wird der Name des Strukturtyps zu einem gültigen Typensymbol.

Beispiel 1

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(setq x 10)
(setq y 34.567)
(setq ch nil)
(setq n 123.78)
(setq bg 11.0e+4)
(setq r 124/2)

(print x)
(print y)
(print n)
(print ch)
(print bg)
(print r)

Wenn Sie auf die Schaltfläche Ausführen klicken oder Strg + E eingeben, führt LISP diese sofort aus und das zurückgegebene Ergebnis lautet:

10 
34.567 
123.78 
NIL 
110000.0 
62

Beispiel 2

Als nächstes überprüfen wir die Typen der Variablen, die im vorherigen Beispiel verwendet wurden. Erstellen Sie eine neue Quellcodedatei mit dem Namen main. lisp und geben Sie den folgenden Code ein.

(defvar x 10)
(defvar y 34.567)
(defvar ch nil)
(defvar n 123.78)
(defvar bg 11.0e+4)
(defvar r 124/2)

(print (type-of x))
(print (type-of y))
(print (type-of n))
(print (type-of ch))
(print (type-of bg))
(print (type-of r))

Wenn Sie auf die Schaltfläche Ausführen klicken oder Strg + E eingeben, führt LISP diese sofort aus und das zurückgegebene Ergebnis lautet:

(INTEGER 0 281474976710655) 
SINGLE-FLOAT 
SINGLE-FLOAT 
NULL 
SINGLE-FLOAT 
(INTEGER 0 281474976710655)

Mit Makros können Sie die Syntax von Standard-LISP erweitern.

Technisch gesehen ist ein Makro eine Funktion, die einen S-Ausdruck als Argumente verwendet und ein LISP-Formular zurückgibt, das dann ausgewertet wird.

Makro definieren

In LISP wird ein benanntes Makro mithilfe eines anderen benannten Makros definiert defmacro. Die Syntax zum Definieren eines Makros lautet -

(defmacro macro-name (parameter-list))
"Optional documentation string."
body-form

Die Makrodefinition besteht aus dem Namen des Makros, einer Parameterliste, einer optionalen Dokumentationszeichenfolge und einer Reihe von Lisp-Ausdrücken, die den vom Makro auszuführenden Job definieren.

Beispiel

Schreiben wir ein einfaches Makro mit dem Namen setTo10, das eine Zahl annimmt und ihren Wert auf 10 setzt.

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(defmacro setTo10(num)
(setq num 10)(print num))
(setq x 25)
(print x)
(setTo10 x)

Wenn Sie auf die Schaltfläche Ausführen klicken oder Strg + E eingeben, führt LISP diese sofort aus und das zurückgegebene Ergebnis lautet:

25
10

In LISP wird jede Variable durch a dargestellt symbol. Der Name der Variablen ist der Name des Symbols und wird in der Speicherzelle des Symbols gespeichert.

Globale Variablen

Globale Variablen haben im gesamten LISP-System permanente Werte und bleiben wirksam, bis ein neuer Wert angegeben wird.

Globale Variablen werden in der Regel mit dem deklariert defvar bauen.

Zum Beispiel

(defvar x 234)
(write x)

Wenn Sie auf die Schaltfläche Ausführen klicken oder Strg + E eingeben, führt LISP diese sofort aus und das zurückgegebene Ergebnis lautet

234

Da es in LISP keine Typdeklaration für Variablen gibt, geben Sie direkt einen Wert für ein Symbol mit dem an setq bauen.

Zum Beispiel

->(setq x 10)

Der obige Ausdruck weist der Variablen x den Wert 10 zu. Sie können auf die Variable verweisen, indem Sie das Symbol selbst als Ausdruck verwenden.

Das symbol-value Mit dieser Funktion können Sie den am Symbolspeicherort gespeicherten Wert extrahieren.

Zum Beispiel

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(setq x 10)
(setq y 20)
(format t "x = ~2d y = ~2d ~%" x y)

(setq x 100)
(setq y 200)
(format t "x = ~2d y = ~2d" x y)

Wenn Sie auf die Schaltfläche Ausführen klicken oder Strg + E eingeben, führt LISP diese sofort aus und das zurückgegebene Ergebnis lautet.

x = 10 y = 20 
x = 100 y = 200

Lokale Variablen

Lokale Variablen werden innerhalb einer bestimmten Prozedur definiert. Die als Argumente in einer Funktionsdefinition genannten Parameter sind ebenfalls lokale Variablen. Auf lokale Variablen kann nur innerhalb der jeweiligen Funktion zugegriffen werden.

Wie die globalen Variablen können auch lokale Variablen mit dem erstellt werden setq bauen.

Es gibt zwei andere Konstrukte - let und prog zum Erstellen lokaler Variablen.

Das let-Konstrukt hat die folgende Syntax.

(let ((var1  val1) (var2  val2).. (varn  valn))<s-expressions>)

Dabei sind var1, var2, ..varn Variablennamen und val1, val2, .. valn die den jeweiligen Variablen zugewiesenen Anfangswerte.

Wann letausgeführt wird, wird jeder Variablen der jeweilige Wert zugewiesen und zuletzt der s-Ausdruck ausgewertet. Der Wert des zuletzt ausgewerteten Ausdrucks wird zurückgegeben.

Wenn Sie keinen Anfangswert für eine Variable angeben, wird dieser zugewiesen nil.

Beispiel

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(let ((x 'a) (y 'b)(z 'c))
(format t "x = ~a y = ~a z = ~a" x y z))

Wenn Sie auf die Schaltfläche Ausführen klicken oder Strg + E eingeben, führt LISP diese sofort aus und das zurückgegebene Ergebnis lautet.

x = A y = B z = C

Das prog Konstrukt hat auch die Liste der lokalen Variablen als erstes Argument, gefolgt vom Hauptteil des prog, und eine beliebige Anzahl von S-Ausdrücken.

Das prog function führt die Liste der s-Ausdrücke nacheinander aus und gibt nil zurück, es sei denn, sie stößt auf einen Funktionsaufruf mit dem Namen return. Dann das Argument der return Funktion wird ausgewertet und zurückgegeben.

Beispiel

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(prog ((x '(a b c))(y '(1 2 3))(z '(p q 10)))
(format t "x = ~a y = ~a z = ~a" x y z))

Wenn Sie auf die Schaltfläche Ausführen klicken oder Strg + E eingeben, führt LISP diese sofort aus und das zurückgegebene Ergebnis lautet.

x = (A B C) y = (1 2 3) z = (P Q 10)

In LISP sind Konstanten Variablen, die ihre Werte während der Programmausführung niemals ändern. Konstanten werden mit dem deklariertdefconstant bauen.

Beispiel

Das folgende Beispiel zeigt, wie eine globale Konstante PI deklariert und später dieser Wert in einer Funktion namens area-circle verwendet wird , die die Fläche eines Kreises berechnet.

Das defun Konstrukt wird zum Definieren einer Funktion verwendet, wir werden es in der untersuchen Functions Kapitel.

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(defconstant PI 3.141592)
(defun area-circle(rad)
   (terpri)
   (format t "Radius: ~5f" rad)
   (format t "~%Area: ~10f" (* PI rad rad)))
(area-circle 10)

Wenn Sie auf die Schaltfläche Ausführen klicken oder Strg + E eingeben, führt LISP diese sofort aus und das zurückgegebene Ergebnis lautet.

Radius:  10.0
Area:   314.1592

Ein Operator ist ein Symbol, das den Compiler anweist, bestimmte mathematische oder logische Manipulationen durchzuführen. LISP ermöglicht zahlreiche Operationen an Daten, die von verschiedenen Funktionen, Makros und anderen Konstrukten unterstützt werden.

Die für Daten zulässigen Vorgänge können wie folgt kategorisiert werden:

  • Rechenoperationen
  • Vergleichsoperationen
  • Logische Operationen
  • Bitweise Operationen

Rechenoperationen

Die folgende Tabelle zeigt alle von LISP unterstützten arithmetischen Operatoren. Variable annehmenA hält 10 und variabel B hält dann 20 -

Show Examples

Operator Beschreibung Beispiel
+ Fügt zwei Operanden hinzu (+ AB) ergibt 30
- - Subtrahiert den zweiten Operanden vom ersten (- AB) ergibt -10
* * Multipliziert beide Operanden (* AB) ergibt 200
/. Teilt den Zähler durch den De-Zähler (/ BA) ergibt 2
mod, rem Modul Operator und Rest nach einer ganzzahligen Division (mod BA) ergibt 0
incf Der Inkrementierungsoperator erhöht den ganzzahligen Wert um das zweite angegebene Argument (vgl. A 3) ergibt 13
decf Der Operator "Dekrementiert" verringert den ganzzahligen Wert um das zweite angegebene Argument (decf A 4) ergibt 9

Vergleichsoperationen

Die folgende Tabelle zeigt alle von LISP unterstützten Vergleichsoperatoren, die zwischen Zahlen vergleichen. Im Gegensatz zu Vergleichsoperatoren in anderen Sprachen können LISP-Vergleichsoperatoren jedoch mehr als zwei Operanden verwenden und arbeiten nur mit Zahlen.

Variable annehmen A hält 10 und variabel B hält 20, dann -

Show Examples

Operator Beschreibung Beispiel
= Überprüft, ob die Werte der Operanden alle gleich sind oder nicht. Wenn ja, wird die Bedingung wahr. (= AB) ist nicht wahr.
/ = Überprüft, ob die Werte der Operanden alle unterschiedlich sind oder nicht. Wenn die Werte nicht gleich sind, wird die Bedingung wahr. (/ = AB) ist wahr.
> Überprüft, ob die Werte der Operanden monoton abnehmen. (> AB) ist nicht wahr.
< Überprüft, ob die Werte der Operanden monoton ansteigen. (<AB) ist wahr.
> = Überprüft, ob der Wert eines linken Operanden größer oder gleich dem Wert des nächsten rechten Operanden ist. Wenn ja, wird die Bedingung wahr. (> = AB) ist nicht wahr.
<= Überprüft, ob der Wert eines linken Operanden kleiner oder gleich dem Wert seines rechten Operanden ist. Wenn ja, wird die Bedingung wahr. (<= AB) ist wahr.
max Es vergleicht zwei oder mehr Argumente und gibt den Maximalwert zurück. (max AB) gibt 20 zurück
Mindest Es vergleicht zwei oder mehr Argumente und gibt den Mindestwert zurück. (min AB) gibt 10 zurück

Logische Operationen für Boolesche Werte

Common LISP bietet drei logische Operatoren: and, or, und notdas arbeitet mit Booleschen Werten. AnnehmenA hat den Wert nil und B hat Wert 5, dann -

Show Examples

Operator Beschreibung Beispiel
und Es sind beliebig viele Argumente erforderlich. Die Argumente werden von links nach rechts ausgewertet. Wenn alle Argumente nicht null sind, wird der Wert des letzten Arguments zurückgegeben. Andernfalls wird nil zurückgegeben. (und AB) geben NIL zurück.
oder Es sind beliebig viele Argumente erforderlich. Die Argumente werden von links nach rechts ausgewertet, bis sie als nicht null ausgewertet werden. In diesem Fall wird der Argumentwert zurückgegeben, andernfalls wird er zurückgegebennil. (oder AB) gibt 5 zurück.
nicht Es braucht ein Argument und kehrt zurück t wenn das Argument zu ausgewertet wird nil. (nicht A) gibt T zurück.

Bitweise Operationen an Zahlen

Bitweise Operatoren arbeiten an Bits und führen eine bitweise Operation durch. Die Wahrheitstabellen für bitweise und oder oder und xor-Operationen lauten wie folgt:

Show Examples

p q p und q p oder q p xor q
0 0 0 0 0
0 1 0 1 1
1 1 1 1 0
1 0 0 1 1
Assume if A = 60; and B = 13; now in binary format they will be as follows:
A = 0011 1100
B = 0000 1101
-----------------
A and B = 0000 1100
A or B = 0011 1101
A xor B = 0011 0001
not A  = 1100 0011

Die von LISP unterstützten bitweisen Operatoren sind in der folgenden Tabelle aufgeführt. Variable annehmenA hält 60 und variabel B hält 13, dann -

Operator Beschreibung Beispiel
logand Dies gibt das bitweise logische UND seiner Argumente zurück. Wenn kein Argument angegeben wird, ist das Ergebnis -1, was eine Identität für diese Operation ist. (logand ab)) ergibt 12
logior Dies gibt das bitweise logische INKLUSIVE ODER seiner Argumente zurück. Wenn kein Argument angegeben wird, ist das Ergebnis Null, was eine Identität für diese Operation ist. (logior ab) ergibt 61
logxor Dies gibt das bitweise logische EXKLUSIVE ODER seiner Argumente zurück. Wenn kein Argument angegeben wird, ist das Ergebnis Null, was eine Identität für diese Operation ist. (logxor ab) ergibt 49
lognor Dies gibt das bitweise NICHT seiner Argumente zurück. Wenn kein Argument angegeben wird, ist das Ergebnis -1, was eine Identität für diese Operation ist. (lognor ab) ergibt -62,
logeqv Dies gibt die bitweise logische Äquivalenz (auch als exklusives Nor bezeichnet) seiner Argumente zurück. Wenn kein Argument angegeben wird, ist das Ergebnis -1, was eine Identität für diese Operation ist. (logeqv ab) ergibt -50

Entscheidungsstrukturen erfordern, dass der Programmierer eine oder mehrere Bedingungen angibt, die vom Programm bewertet oder getestet werden sollen, zusammen mit einer Anweisung oder Anweisungen, die ausgeführt werden sollen, wenn die Bedingung als wahr bestimmt wird, und optional anderen Anweisungen, die ausgeführt werden sollen, wenn die Bedingung ausgeführt wird wird als falsch bestimmt.

Es folgt die allgemeine Form einer typischen Entscheidungsstruktur, die in den meisten Programmiersprachen zu finden ist:

LISP bietet die folgenden Arten von Entscheidungskonstrukten. Klicken Sie auf die folgenden Links, um deren Details zu überprüfen.

Sr.Nr. Konstrukt & Beschreibung
1 cond

Dieses Konstrukt wird zum Überprüfen mehrerer Testaktionsklauseln verwendet. Es kann mit den verschachtelten if-Anweisungen in anderen Programmiersprachen verglichen werden.

2 wenn

Das if-Konstrukt hat verschiedene Formen. In einfachster Form folgen eine Testklausel, eine Testaktion und einige andere Folgeaktionen. Wenn die Testklausel als wahr ausgewertet wird, wird die Testaktion anderweitig ausgeführt, und die nachfolgende Klausel wird ausgewertet.

3 wann

In der einfachsten Form folgen eine Testklausel und eine Testaktion. Wenn die Testklausel als wahr ausgewertet wird, wird die Testaktion anderweitig ausgeführt, und die nachfolgende Klausel wird ausgewertet.

4 Fall

Dieses Konstrukt implementiert mehrere Testaktionsklauseln wie das cond-Konstrukt. Es wertet jedoch ein Schlüsselformular aus und ermöglicht mehrere Aktionsklauseln, die auf der Bewertung dieses Schlüsselformulars basieren.

Es kann vorkommen, dass Sie einen Codeblock mehrmals ausführen müssen. Mit einer Schleifenanweisung können wir eine Anweisung oder eine Gruppe von Anweisungen mehrmals ausführen. Im Folgenden wird die allgemeine Form einer Schleifenanweisung in den meisten Programmiersprachen beschrieben.

LISP bietet die folgenden Arten von Konstrukten, um die Schleifenanforderungen zu erfüllen. Klicken Sie auf die folgenden Links, um deren Details zu überprüfen.

Sr.Nr. Konstrukt & Beschreibung
1 Schleife

Das loopKonstrukt ist die einfachste Form der Iteration, die von LISP bereitgestellt wird. In seiner einfachsten Form können Sie einige Anweisungen wiederholt ausführen, bis sie eine findenreturn Erklärung.

2 Schleife für

Mit der Schleife für das Konstrukt können Sie eine for-Schleife-ähnliche Iteration implementieren, wie sie in anderen Sprachen am häufigsten verwendet wird.

3 tun

Das do-Konstrukt wird auch zum Durchführen einer Iteration mit LISP verwendet. Es bietet eine strukturierte Form der Iteration.

4 dotimes

Das Dotimes-Konstrukt ermöglicht das Schleifen für eine feste Anzahl von Iterationen.

5 Dolist

Das Dolistenkonstrukt ermöglicht die Iteration durch jedes Element einer Liste.

Anmutig aus einem Block herauskommen

Das block und return-from Mit dieser Option können Sie verschachtelte Blöcke im Fehlerfall ordnungsgemäß verlassen.

Das blockMit dieser Funktion können Sie einen benannten Block mit einem Text erstellen, der aus null oder mehr Anweisungen besteht. Syntax ist -

(block block-name(
...
...
))

Das return-from Die Funktion verwendet einen Blocknamen und einen optionalen (der Standardwert ist Null) Rückgabewert.

Das folgende Beispiel zeigt dies -

Beispiel

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein:

(defun demo-function (flag)
   (print 'entering-outer-block)
   
   (block outer-block
      (print 'entering-inner-block)
      (print (block inner-block

         (if flag
            (return-from outer-block 3)
            (return-from inner-block 5)
         )

         (print 'This-wil--not-be-printed))
      )

      (print 'left-inner-block)
      (print 'leaving-outer-block)
   t)
)
(demo-function t)
(terpri)
(demo-function nil)

Wenn Sie auf die Schaltfläche Ausführen klicken oder Strg + E eingeben, führt LISP diese sofort aus und das zurückgegebene Ergebnis lautet:

ENTERING-OUTER-BLOCK 
ENTERING-INNER-BLOCK 

ENTERING-OUTER-BLOCK 
ENTERING-INNER-BLOCK 
5 
LEFT-INNER-BLOCK 
LEAVING-OUTER-BLOCK

Eine Funktion ist eine Gruppe von Anweisungen, die zusammen eine Aufgabe ausführen.

Sie können Ihren Code in separate Funktionen aufteilen. Wie Sie Ihren Code auf verschiedene Funktionen aufteilen, liegt bei Ihnen. Logischerweise erfolgt die Aufteilung jedoch normalerweise so, dass jede Funktion eine bestimmte Aufgabe ausführt.

Funktionen in LISP definieren

Das Makro mit dem Namen defunwird zum Definieren von Funktionen verwendet. Dasdefun Makro benötigt drei Argumente -

  • Name der Funktion
  • Parameter der Funktion
  • Körper der Funktion

Syntax für defun ist -

(defun name (parameter-list) "Optional documentation string." body)

Lassen Sie uns das Konzept anhand einfacher Beispiele veranschaulichen.

Beispiel 1

Schreiben wir eine Funktion namens averagenum , die den Durchschnitt von vier Zahlen druckt. Wir werden diese Nummern als Parameter senden.

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(defun averagenum (n1 n2 n3 n4)
   (/ ( + n1 n2 n3 n4) 4)
)
(write(averagenum 10 20 30 40))

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

25

Beispiel 2

Definieren und rufen wir eine Funktion auf, die die Fläche eines Kreises berechnet, wenn der Radius des Kreises als Argument angegeben wird.

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(defun area-circle(rad)
   "Calculates area of a circle with given radius"
   (terpri)
   (format t "Radius: ~5f" rad)
   (format t "~%Area: ~10f" (* 3.141592 rad rad))
)
(area-circle 10)

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

Radius:  10.0
Area:   314.1592

Bitte beachten Sie, dass -

  • Sie können eine leere Liste als Parameter angeben. Dies bedeutet, dass die Funktion keine Argumente akzeptiert. Die Liste ist leer und als () geschrieben.

  • LISP erlaubt auch optionale, Mehrfach- und Schlüsselwortargumente.

  • Die Dokumentationszeichenfolge beschreibt den Zweck der Funktion. Es ist mit dem Namen der Funktion verknüpft und kann über die abgerufen werdendocumentation Funktion.

  • Der Hauptteil der Funktion kann aus einer beliebigen Anzahl von Lisp-Ausdrücken bestehen.

  • Der Wert des letzten Ausdrucks im Body wird als Wert der Funktion zurückgegeben.

  • Sie können auch einen Wert aus der Funktion mit dem zurückgeben return-from Spezialoperator.

Lassen Sie uns die obigen Konzepte kurz diskutieren. Klicken Sie auf die folgenden Links, um Details zu finden -

  • Optionale Parameter

  • Ruheparameter

  • Schlüsselwortparameter

  • Werte von einer Funktion zurückgeben

  • Lambda-Funktionen

  • Zuordnungsfunktionen

Prädikate sind Funktionen, die ihre Argumente für bestimmte Bedingungen testen und null zurückgeben, wenn die Bedingung falsch ist, oder wenn ein Wert ungleich null ist, ist die Bedingung wahr.

Die folgende Tabelle zeigt einige der am häufigsten verwendeten Prädikate -

Sr.Nr. Prädikat & Beschreibung
1

atom

Es nimmt ein Argument und gibt t zurück, wenn das Argument ein Atom ist, oder nil, wenn nicht.

2

equal

Es dauert zwei Argumente und gibt zurück t wenn sie strukturell gleich sind oder nil Andernfalls.

3

eq

Es dauert zwei Argumente und gibt zurück t Wenn es sich um dieselben identischen Objekte handelt, teilen Sie sich denselben Speicherort oder nil Andernfalls.

4

eql

Es dauert zwei Argumente und gibt zurück t wenn die Argumente sind eqoder wenn es sich um Zahlen desselben Typs mit demselben Wert handelt oder wenn es sich um Zeichenobjekte handelt, die dasselbe Zeichen darstellen, oder nil Andernfalls.

5

evenp

Es nimmt ein numerisches Argument und kehrt zurück t wenn das Argument gerade Zahl ist oder nil wenn nicht anders.

6

oddp

Es nimmt ein numerisches Argument und kehrt zurück t wenn das Argument eine ungerade Zahl ist oder nil wenn nicht anders.

7

zerop

Es nimmt ein numerisches Argument und kehrt zurück t wenn das Argument Null ist oder nil wenn nicht anders.

8

null

Es braucht ein Argument und kehrt zurück t Wenn das Argument null ergibt, wird es zurückgegeben nil.

9

listp

Es braucht ein Argument und kehrt zurück t Wenn das Argument zu einer Liste ausgewertet wird, wird es zurückgegeben nil.

10

greaterp

Es nimmt ein oder mehrere Argumente und kehrt zurück t wenn entweder ein einzelnes Argument vorhanden ist oder die Argumente von links nach rechts sukzessive größer sind, oder nil wenn nicht anders.

11

lessp

Es nimmt ein oder mehrere Argumente und kehrt zurück t wenn entweder ein einzelnes Argument vorhanden ist oder die Argumente von links nach rechts sukzessive kleiner sind, oder nil wenn nicht anders.

12

numberp

Es braucht ein Argument und kehrt zurück t wenn das Argument eine Zahl ist oder nil wenn nicht anders.

13

symbolp

Es braucht ein Argument und kehrt zurück t Wenn das Argument ein Symbol ist, wird es zurückgegeben nil.

14

integerp

Es braucht ein Argument und kehrt zurück t Wenn das Argument eine Ganzzahl ist, wird es zurückgegeben nil.

15

rationalp

Es braucht ein Argument und kehrt zurück t Wenn das Argument eine rationale Zahl ist, entweder ein Verhältnis oder eine Zahl, wird es zurückgegeben nil.

16

floatp

Es braucht ein Argument und kehrt zurück t Wenn das Argument eine Gleitkommazahl ist, wird es zurückgegeben nil.

17

realp

Es braucht ein Argument und kehrt zurück t Wenn das Argument eine reelle Zahl ist, wird es zurückgegeben nil.

18

complexp

Es braucht ein Argument und kehrt zurück t Wenn das Argument eine komplexe Zahl ist, wird es zurückgegeben nil.

19

characterp

Es braucht ein Argument und kehrt zurück t Wenn das Argument ein Zeichen ist, wird es zurückgegeben nil.

20

stringp

Es braucht ein Argument und kehrt zurück t Wenn das Argument ein Zeichenfolgenobjekt ist, wird es zurückgegeben nil.

21

arrayp

Es braucht ein Argument und kehrt zurück t Wenn das Argument ein Array-Objekt ist, wird es zurückgegeben nil.

22

packagep

Es braucht ein Argument und kehrt zurück t Wenn das Argument ein Paket ist, wird es zurückgegeben nil.

Beispiel 1

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(write (atom 'abcd))
(terpri)
(write (equal 'a 'b))
(terpri)
(write (evenp 10))
(terpri)
(write (evenp 7 ))
(terpri)
(write (oddp 7 ))
(terpri)
(write (zerop 0.0000000001))
(terpri)
(write (eq 3 3.0 ))
(terpri)
(write (equal 3 3.0 ))
(terpri)
(write (null nil ))

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

T
NIL
T
NIL
T
NIL
NIL
NIL
T

Beispiel 2

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(defun factorial (num)
   (cond ((zerop num) 1)
      (t ( * num (factorial (- num 1))))
   )
)
(setq n 6)
(format t "~% Factorial ~d is: ~d" n (factorial n))

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

Factorial 6 is: 720

Common Lisp definiert verschiedene Arten von Zahlen. Dasnumber Der Datentyp enthält verschiedene Arten von Nummern, die von LISP unterstützt werden.

Die von LISP unterstützten Nummerntypen sind -

  • Integers
  • Ratios
  • Gleitkommazahlen
  • Komplexe Zahlen

Das folgende Diagramm zeigt die Zahlenhierarchie und verschiedene numerische Datentypen, die in LISP verfügbar sind -

Verschiedene numerische Typen in LISP

In der folgenden Tabelle werden verschiedene in LISP verfügbare Nummerntypdaten beschrieben.

Sr.Nr. Datentyp & Beschreibung
1

fixnum

Dieser Datentyp stellt Ganzzahlen dar, die nicht zu groß sind und meist im Bereich von -215 bis 215-1 liegen (er ist maschinenabhängig).

2

bignum

Dies sind sehr große Zahlen, deren Größe durch die für LISP zugewiesene Speichermenge begrenzt ist. Es handelt sich nicht um feste Zahlen.

3

ratio

Stellt das Verhältnis zweier Zahlen in der Zähler / Nenner-Form dar. Die / -Funktion erzeugt das Ergebnis immer in Verhältnissen, wenn ihre Argumente ganze Zahlen sind.

4

float

Es repräsentiert nicht ganzzahlige Zahlen. Es gibt vier Float-Datentypen mit zunehmender Genauigkeit.

5

complex

Es stellt komplexe Zahlen dar, die mit #c bezeichnet sind. Der Realteil und der Imaginärteil können entweder rationale oder Gleitkommazahlen sein.

Beispiel

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(write (/ 1 2))
(terpri)
(write ( + (/ 1 2) (/ 3 4)))
(terpri)
(write ( + #c( 1 2) #c( 3 -4)))

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

1/2
5/4
#C(4 -2)

Zahlenfunktionen

In der folgenden Tabelle werden einige häufig verwendete numerische Funktionen beschrieben.

Sr.Nr. Bedienungsanleitung
1

+, -, *, /

Jeweils arithmetische Operationen

2

sin, cos, tan, acos, asin, atan

Jeweils trigonometrische Funktionen.

3

sinh, cosh, tanh, acosh, asinh, atanh

Entsprechende hyperbolische Funktionen.

4

exp

Exponentiationsfunktion. Berechnet e x

5

expt

Exponentiationsfunktion, nimmt Basis und Macht beide.

6

sqrt

Es berechnet die Quadratwurzel einer Zahl.

7

log

Logarithmische Funktion. Wenn ein Parameter angegeben wird, berechnet er seinen natürlichen Logarithmus, andernfalls wird der zweite Parameter als Basis verwendet.

8

conjugate

Es berechnet das komplexe Konjugat einer Zahl. Bei einer reellen Zahl wird die Zahl selbst zurückgegeben.

9

abs

Es gibt den absoluten Wert (oder die Größe) einer Zahl zurück.

10

gcd

Es berechnet den größten gemeinsamen Teiler der angegebenen Zahlen.

11

lcm

Es berechnet das kleinste gemeinsame Vielfache der angegebenen Zahlen.

12

isqrt

Es gibt die größte ganze Zahl, die kleiner oder gleich der exakten Quadratwurzel einer gegebenen natürlichen Zahl ist.

13

floor, ceiling, truncate, round

Alle diese Funktionen verwenden zwei Argumente als Zahl und geben den Quotienten zurück. floor Gibt die größte Ganzzahl zurück, die nicht größer als das Verhältnis ist. ceiling wählt die kleinere Ganzzahl, die größer als das Verhältnis ist, truncate wählt die ganze Zahl mit dem gleichen Vorzeichen wie das Verhältnis mit dem größten absoluten Wert, der kleiner als der absolute Wert des Verhältnisses ist, und round wählt eine Ganzzahl, die dem Verhältnis am nächsten kommt.

14

ffloor, fceiling, ftruncate, fround

Funktioniert wie oben, gibt jedoch den Quotienten als Gleitkommazahl zurück.

15

mod, rem

Gibt den Rest in einer Divisionsoperation zurück.

16

float

Konvertiert eine reelle Zahl in eine Gleitkommazahl.

17

rational, rationalize

Wandelt eine reelle Zahl in eine rationale Zahl um.

18

numerator, denominator

Gibt die jeweiligen Teile einer rationalen Zahl zurück.

19

realpart, imagpart

Gibt den Real- und Imaginärteil einer komplexen Zahl zurück.

Beispiel

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(write (/ 45 78))
(terpri)
(write (floor 45 78))
(terpri)
(write (/ 3456 75))
(terpri)
(write (floor 3456 75))
(terpri)
(write (ceiling 3456 75))
(terpri)
(write (truncate 3456 75))
(terpri)
(write (round 3456 75))
(terpri)
(write (ffloor 3456 75))
(terpri)
(write (fceiling 3456 75))
(terpri)
(write (ftruncate 3456 75))
(terpri)
(write (fround 3456 75))
(terpri)
(write (mod 3456 75))
(terpri)
(setq c (complex 6 7))
(write c)
(terpri)
(write (complex 5 -9))
(terpri)
(write (realpart c))
(terpri)
(write (imagpart c))

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

15/26
0
1152/25
46
47
46
46
46.0
47.0
46.0
46.0
6
#C(6 7)
#C(5 -9)
6
7

In LISP werden Zeichen als Datenobjekte vom Typ dargestellt character.

Sie können ein Zeichenobjekt vor # \ vor dem Zeichen selbst bezeichnen. Zum Beispiel bedeutet # \ a das Zeichen a.

Leerzeichen und andere Sonderzeichen können durch Vorangestelltes # \ vor dem Namen des Zeichens gekennzeichnet werden. Beispielsweise steht # \ SPACE für das Leerzeichen.

Das folgende Beispiel zeigt dies -

Beispiel

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(write 'a)
(terpri)
(write #\a)
(terpri)
(write-char #\a)
(terpri)
(write-char 'a)

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

A
#\a
a
*** - WRITE-CHAR: argument A is not a character

Spezielle Charaktere

Mit Common LISP können Sie die folgenden Sonderzeichen in Ihrem Code verwenden. Sie werden als Semi-Standard-Zeichen bezeichnet.

  • #\Backspace
  • #\Tab
  • #\Linefeed
  • #\Page
  • #\Return
  • #\Rubout

Zeichenvergleichsfunktionen

Numerische Vergleichsfunktionen und Operatoren wie <und> funktionieren nicht für Zeichen. Common LISP bietet zwei weitere Funktionssätze zum Vergleichen von Zeichen in Ihrem Code.

Ein Satz unterscheidet zwischen Groß- und Kleinschreibung und der andere zwischen Groß- und Kleinschreibung.

Die folgende Tabelle enthält die Funktionen -

Groß- und Kleinschreibung beachten Funktionen, bei denen die Groß- und Kleinschreibung nicht berücksichtigt wird Beschreibung
char = char-gleich Überprüft, ob die Werte der Operanden alle gleich sind oder nicht. Wenn ja, wird die Bedingung wahr.
char / = char-ungleich Überprüft, ob die Werte der Operanden alle unterschiedlich sind oder nicht. Wenn die Werte nicht gleich sind, wird die Bedingung wahr.
char < char-lessp Überprüft, ob die Werte der Operanden monoton abnehmen.
char> char-Greaterp Überprüft, ob die Werte der Operanden monoton ansteigen.
char <= char-not-Greaterp Überprüft, ob der Wert eines linken Operanden größer oder gleich dem Wert des nächsten rechten Operanden ist. Wenn ja, wird die Bedingung wahr.
char> = char-not-lessp Überprüft, ob der Wert eines linken Operanden kleiner oder gleich dem Wert seines rechten Operanden ist. Wenn ja, wird die Bedingung wahr.

Beispiel

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

; case-sensitive comparison
(write (char= #\a #\b))
(terpri)
(write (char= #\a #\a))
(terpri)
(write (char= #\a #\A))
(terpri)
   
;case-insensitive comparision
(write (char-equal #\a #\A))
(terpri)
(write (char-equal #\a #\b))
(terpri)
(write (char-lessp #\a #\b #\c))
(terpri)
(write (char-greaterp #\a #\b #\c))

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

NIL
T
NIL
T
NIL
T
NIL

Mit LISP können Sie ein- oder mehrdimensionale Arrays mithilfe von definieren make-arrayFunktion. Ein Array kann jedes LISP-Objekt als seine Elemente speichern.

Alle Arrays bestehen aus zusammenhängenden Speicherstellen. Die niedrigste Adresse entspricht dem ersten Element und die höchste Adresse dem letzten Element.

Die Anzahl der Dimensionen eines Arrays wird als Rang bezeichnet.

In LISP wird ein Array-Element durch eine Folge nicht negativer ganzzahliger Indizes angegeben. Die Länge der Sequenz muss dem Rang des Arrays entsprechen. Die Indizierung beginnt bei Null.

Um beispielsweise ein Array mit 10 Zellen mit dem Namen my-array zu erstellen, können wir schreiben:

(setf my-array (make-array '(10)))

Die aref-Funktion ermöglicht den Zugriff auf den Inhalt der Zellen. Es werden zwei Argumente benötigt, der Name des Arrays und der Indexwert.

Um beispielsweise auf den Inhalt der zehnten Zelle zuzugreifen, schreiben wir:

(aref my-array 9)

Beispiel 1

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(write (setf my-array (make-array '(10))))
(terpri)
(setf (aref my-array 0) 25)
(setf (aref my-array 1) 23)
(setf (aref my-array 2) 45)
(setf (aref my-array 3) 10)
(setf (aref my-array 4) 20)
(setf (aref my-array 5) 17)
(setf (aref my-array 6) 25)
(setf (aref my-array 7) 19)
(setf (aref my-array 8) 67)
(setf (aref my-array 9) 30)
(write my-array)

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

#(NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL)
#(25 23 45 10 20 17 25 19 67 30)

Beispiel 2

Lassen Sie uns ein 3-mal-3-Array erstellen.

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(setf x (make-array '(3 3) 
   :initial-contents '((0 1 2 ) (3 4 5) (6 7 8)))
)
(write x)

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

#2A((0 1 2) (3 4 5) (6 7 8))

Beispiel 3

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(setq a (make-array '(4 3)))
(dotimes (i 4)
   (dotimes (j 3)
      (setf (aref a i j) (list i 'x j '= (* i j)))
   )
)
(dotimes (i 4)
   (dotimes (j 3)
      (print (aref a i j))
   )
)

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

(0 X 0 = 0) 
(0 X 1 = 0) 
(0 X 2 = 0) 
(1 X 0 = 0) 
(1 X 1 = 1) 
(1 X 2 = 2) 
(2 X 0 = 0) 
(2 X 1 = 2) 
(2 X 2 = 4) 
(3 X 0 = 0) 
(3 X 1 = 3) 
(3 X 2 = 6)

Vollständige Syntax für die Funktion make-array

Die Funktion make-array akzeptiert viele andere Argumente. Schauen wir uns die vollständige Syntax dieser Funktion an -

make-array dimensions :element-type :initial-element :initial-contents :adjustable :fill-pointer  :displaced-to :displaced-index-offset

Mit Ausnahme des Dimensionsarguments sind alle anderen Argumente Schlüsselwörter. Die folgende Tabelle enthält eine kurze Beschreibung der Argumente.

Sr.Nr. Argument & Beschreibung
1

dimensions

Es gibt die Abmessungen des Arrays an. Es ist eine Zahl für ein eindimensionales Array und eine Liste für ein mehrdimensionales Array.

2

:element-type

Dies ist der Typbezeichner. Der Standardwert ist T, dh ein beliebiger Typ

3

:initial-element

Anfangselementwert. Es wird ein Array mit allen Elementen erstellt, die auf einen bestimmten Wert initialisiert wurden.

4

:initial-content

Anfangsinhalt als Objekt.

5

:adjustable

Es hilft beim Erstellen eines veränderbaren (oder anpassbaren) Vektors, dessen Größe dem zugrunde liegenden Speicher geändert werden kann. Das Argument ist ein boolescher Wert, der angibt, ob das Array anpassbar ist oder nicht. Der Standardwert ist NIL.

6

:fill-pointer

Es verfolgt die Anzahl der Elemente, die tatsächlich in einem veränderbaren Vektor gespeichert sind.

7

:displaced-to

Es hilft beim Erstellen eines verschobenen Arrays oder eines gemeinsam genutzten Arrays, das seinen Inhalt mit dem angegebenen Array teilt. Beide Arrays sollten denselben Elementtyp haben. Die Option: verschoben an darf darf nicht mit der Option: initial-element oder: initial-content verwendet werden. Dieses Argument ist standardmäßig null.

8

:displaced-index-offset

Es gibt den Indexversatz des erstellten gemeinsam genutzten Arrays an.

Beispiel 4

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(setq myarray (make-array '(3 2 3) 
   :initial-contents 
   '(((a b c) (1 2 3)) 
      ((d e f) (4 5 6)) 
      ((g h i) (7 8 9)) 
   ))
) 
(setq array2 (make-array 4 :displaced-to myarray :displaced-index-offset 2)) 
(write myarray)
(terpri)
(write array2)

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

#3A(((A B C) (1 2 3)) ((D E F) (4 5 6)) ((G H I) (7 8 9)))
#(C 1 2 3)

Wenn das verschobene Array zweidimensional ist -

(setq myarray (make-array '(3 2 3) 
   :initial-contents 
   '(((a b c) (1 2 3)) 
      ((d e f) (4 5 6)) 
      ((g h i) (7 8 9)) 
   ))
) 
(setq array2 (make-array '(3 2) :displaced-to myarray :displaced-index-offset 2)) 
(write myarray)
(terpri)
(write array2)

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

#3A(((A B C) (1 2 3)) ((D E F) (4 5 6)) ((G H I) (7 8 9)))
#2A((C 1) (2 3) (D E))

Ändern wir den versetzten Indexversatz auf 5 -

(setq myarray (make-array '(3 2 3) 
   :initial-contents 
   '(((a b c) (1 2 3)) 
      ((d e f) (4 5 6)) 
      ((g h i) (7 8 9)) 
   ))
) 
(setq array2 (make-array '(3 2) :displaced-to myarray :displaced-index-offset 5)) 
(write myarray)
(terpri)
(write array2)

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

#3A(((A B C) (1 2 3)) ((D E F) (4 5 6)) ((G H I) (7 8 9)))
#2A((3 D) (E F) (4 5))

Beispiel 5

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

;a one dimensional array with 5 elements, 
;initail value 5
(write (make-array 5 :initial-element 5))
(terpri)

;two dimensional array, with initial element a
(write (make-array '(2 3) :initial-element 'a))
(terpri)

;an array of capacity 14, but fill pointer 5, is 5
(write(length (make-array 14 :fill-pointer 5)))
(terpri)

;however its length is 14
(write (array-dimensions (make-array 14 :fill-pointer 5)))
(terpri)

; a bit array with all initial elements set to 1
(write(make-array 10 :element-type 'bit :initial-element 1))
(terpri)

; a character array with all initial elements set to a
; is a string actually
(write(make-array 10 :element-type 'character :initial-element #\a)) 
(terpri)

; a two dimensional array with initial values a
(setq myarray (make-array '(2 2) :initial-element 'a :adjustable t))
(write myarray)
(terpri)

;readjusting the array
(adjust-array myarray '(1 3) :initial-element 'b) 
(write myarray)

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

#(5 5 5 5 5)
#2A((A A A) (A A A))
5
(14)
#*1111111111
"aaaaaaaaaa"
#2A((A A) (A A))
#2A((A A B))

Zeichenfolgen in Common Lisp sind Vektoren, dh eindimensionale Zeichenfolgen.

String-Literale werden in doppelte Anführungszeichen gesetzt. Jedes vom Zeichensatz unterstützte Zeichen kann in doppelte Anführungszeichen gesetzt werden, um eine Zeichenfolge zu erstellen, mit Ausnahme des doppelten Anführungszeichens (") und des Escape-Zeichens (\). Sie können diese jedoch einschließen, indem Sie sie mit einem Backslash (\) maskieren.

Beispiel

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(write-line "Hello World")
(write-line "Welcome to Tutorials Point")

;escaping the double quote character
(write-line "Welcome to \"Tutorials Point\"")

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

Hello World
Welcome to Tutorials Point
Welcome to "Tutorials Point"

String-Vergleichsfunktionen

Numerische Vergleichsfunktionen und Operatoren wie <und> funktionieren nicht für Zeichenfolgen. Common LISP bietet zwei weitere Funktionssätze zum Vergleichen von Zeichenfolgen in Ihrem Code. Ein Satz unterscheidet zwischen Groß- und Kleinschreibung und der andere zwischen Groß- und Kleinschreibung.

Die folgende Tabelle enthält die Funktionen -

Groß- und Kleinschreibung beachten Funktionen, bei denen die Groß- und Kleinschreibung nicht berücksichtigt wird Beschreibung
string = string-gleich Überprüft, ob die Werte der Operanden alle gleich sind oder nicht. Wenn ja, wird die Bedingung wahr.
Zeichenfolge / = Zeichenfolge ungleich Überprüft, ob die Werte der Operanden alle unterschiedlich sind oder nicht. Wenn die Werte nicht gleich sind, wird die Bedingung wahr.
Zeichenfolge < string-lessp Überprüft, ob die Werte der Operanden monoton abnehmen.
Zeichenfolge> string-Greaterp Überprüft, ob die Werte der Operanden monoton ansteigen.
Zeichenfolge <= Zeichenfolge-nicht-größerp Überprüft, ob der Wert eines linken Operanden größer oder gleich dem Wert des nächsten rechten Operanden ist. Wenn ja, wird die Bedingung wahr.
Zeichenfolge> = string-not-lessp Überprüft, ob der Wert eines linken Operanden kleiner oder gleich dem Wert seines rechten Operanden ist. Wenn ja, wird die Bedingung wahr.

Beispiel

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

; case-sensitive comparison
(write (string= "this is test" "This is test"))
(terpri)
(write (string> "this is test" "This is test"))
(terpri)
(write (string< "this is test" "This is test"))
(terpri)

;case-insensitive comparision
(write (string-equal "this is test" "This is test"))
(terpri)
(write (string-greaterp "this is test" "This is test"))
(terpri)
(write (string-lessp "this is test" "This is test"))
(terpri)

;checking non-equal
(write (string/= "this is test" "this is Test"))
(terpri)
(write (string-not-equal "this is test" "This is test"))
(terpri)
(write (string/= "lisp" "lisping"))
(terpri)
(write (string/= "decent" "decency"))

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

NIL
0
NIL
T
NIL
NIL
8
NIL
4
5

Fallsteuerungsfunktionen

In der folgenden Tabelle werden die Funktionen zur Fallsteuerung beschrieben.

Sr.Nr. Bedienungsanleitung
1

string-upcase

Konvertiert die Zeichenfolge in Großbuchstaben

2

string-downcase

Konvertiert die Zeichenfolge in Kleinbuchstaben

3

string-capitalize

Großschreibt jedes Wort in der Zeichenfolge

Beispiel

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(write-line (string-upcase "a big hello from tutorials point"))
(write-line (string-capitalize "a big hello from tutorials point"))

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

A BIG HELLO FROM TUTORIALS POINT
A Big Hello From Tutorials Point

Strings schneiden

In der folgenden Tabelle werden die Funktionen zum Trimmen von Zeichenfolgen beschrieben.

Sr.Nr. Bedienungsanleitung
1

string-trim

Es verwendet eine Zeichenfolge (n) als erstes Argument und eine Zeichenfolge als zweites Argument und gibt eine Teilzeichenfolge zurück, in der alle Zeichen im ersten Argument aus der Argumentzeichenfolge entfernt werden.

2

String-left-trim

Es verwendet eine Zeichenfolge (n) als erstes Argument und eine Zeichenfolge als zweites Argument und gibt eine Teilzeichenfolge zurück, in der alle Zeichen, die sich im ersten Argument befinden, am Anfang der Argumentzeichenfolge entfernt werden.

3

String-right-trim

Es verwendet eine Zeichenfolge als erstes Argument und eine Zeichenfolge als zweites Argument und gibt eine Teilzeichenfolge zurück, in der alle Zeichen im ersten Argument am Ende der Argumentzeichenfolge entfernt werden.

Beispiel

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(write-line (string-trim " " "   a big hello from tutorials point   "))
(write-line (string-left-trim " " "   a big hello from tutorials point   "))
(write-line (string-right-trim " " "   a big hello from tutorials point   "))
(write-line (string-trim " a" "   a big hello from tutorials point   "))

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

a big hello from tutorials point
a big hello from tutorials point   
   a big hello from tutorials point
big hello from tutorials point

Andere String-Funktionen

Strings in LISP sind Arrays und damit auch Sequenzen. Wir werden diese Datentypen in den kommenden Tutorials behandeln. Alle Funktionen, die für Arrays und Sequenzen gelten, gelten auch für Zeichenfolgen. Wir werden jedoch einige häufig verwendete Funktionen anhand verschiedener Beispiele demonstrieren.

Länge berechnen

Das length Funktion berechnet die Länge eines Strings.

Substring extrahieren

Das subseq Die Funktion gibt eine Unterzeichenfolge zurück (da eine Zeichenfolge auch eine Sequenz ist), die an einem bestimmten Index beginnt und bis zu einem bestimmten Endindex oder dem Ende der Zeichenfolge fortgesetzt wird.

Zugriff auf ein Zeichen in einer Zeichenfolge

Das char Funktion ermöglicht den Zugriff auf einzelne Zeichen einer Zeichenfolge.

Example

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(write (length "Hello World"))
(terpri)
(write-line (subseq "Hello World" 6))
(write (char "Hello World" 6))

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

11
World
#\W

Sortieren und Zusammenführen von Strings

Das sortFunktion ermöglicht das Sortieren einer Zeichenfolge. Es verwendet eine Sequenz (Vektor oder Zeichenfolge) und ein Prädikat mit zwei Argumenten und gibt eine sortierte Version der Sequenz zurück.

Das merge Die Funktion verwendet zwei Sequenzen und ein Prädikat und gibt eine Sequenz zurück, die durch Zusammenführen der beiden Sequenzen gemäß dem Prädikat erzeugt wird.

Example

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

;sorting the strings
(write (sort (vector "Amal" "Akbar" "Anthony") #'string<))
(terpri)

;merging the strings
(write (merge 'vector (vector "Rishi" "Zara" "Priyanka") 
   (vector "Anju" "Anuj" "Avni") #'string<))

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

#("Akbar" "Amal" "Anthony")
#("Anju" "Anuj" "Avni" "Rishi" "Zara" "Priyanka")

String umkehren

Das reverse Funktion kehrt einen String um.

Erstellen Sie beispielsweise eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(write-line (reverse "Are we not drawn onward, we few, drawn onward to new era"))

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

are wen ot drawno nward ,wef ew ,drawno nward ton ew erA

Verketten von Strings

Die Verkettungsfunktion verkettet zwei Zeichenfolgen. Dies ist eine generische Sequenzfunktion, und Sie müssen den Ergebnistyp als erstes Argument angeben.

Erstellen Sie beispielsweise eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(write-line (concatenate 'string "Are we not drawn onward, " "we few, drawn onward to new era"))

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

Are we not drawn onward, we few, drawn onward to new era

Sequenz ist ein abstrakter Datentyp in LISP. Vektoren und Listen sind die beiden konkreten Untertypen dieses Datentyps. Alle für den Sequenzdatentyp definierten Funktionen werden tatsächlich auf alle Vektoren und Listentypen angewendet.

In diesem Abschnitt werden die am häufigsten verwendeten Funktionen für Sequenzen erläutert.

Bevor wir mit verschiedenen Arten der Manipulation von Sequenzen (dh Vektoren und Listen) beginnen, werfen wir einen Blick auf die Liste aller verfügbaren Funktionen.

Erstellen einer Sequenz

Mit der Funktion make-sequence können Sie eine Sequenz eines beliebigen Typs erstellen. Die Syntax für diese Funktion lautet -

make-sequence sqtype sqsize &key :initial-element

Es wird eine Sequenz vom Typ sqtype und von der Länge sqsize erstellt.

Sie können optional einen Wert mit dem Argument : initial-element angeben. Anschließend wird jedes der Elemente mit diesem Wert initialisiert.

Erstellen Sie beispielsweise eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(write (make-sequence '(vector float) 
   10 
   :initial-element 1.0))

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

#(1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0)

Allgemeine Funktionen für Sequenzen

Sr.Nr. Bedienungsanleitung
1

elt

Es ermöglicht den Zugriff auf einzelne Elemente über einen ganzzahligen Index.

2

length

Es gibt die Länge einer Sequenz zurück.

3

subseq

Es gibt eine Teilsequenz zurück, indem die Teilsequenz beginnend mit einem bestimmten Index extrahiert und bis zu einem bestimmten Endindex oder dem Ende der Sequenz fortgesetzt wird.

4

copy-seq

Es gibt eine Sequenz zurück, die dieselben Elemente wie das Argument enthält.

5

fill

Es wird verwendet, um mehrere Elemente einer Sequenz auf einen einzigen Wert zu setzen.

6

replace

Es dauert zwei Sequenzen und die erste Argumentsequenz wird destruktiv modifiziert, indem aufeinanderfolgende Elemente aus der zweiten Argumentsequenz in sie kopiert werden.

7

count

Es nimmt einen Artikel und eine Sequenz und gibt zurück, wie oft der Artikel in der Sequenz erscheint.

8

reverse

Es wird eine Sequenz zurückgegeben, die dieselben Elemente des Arguments enthält, jedoch in umgekehrter Reihenfolge.

9

nreverse

Es wird dieselbe Sequenz zurückgegeben, die dieselben Elemente wie die Sequenz enthält, jedoch in umgekehrter Reihenfolge.

10

concatenate

Es wird eine neue Sequenz erstellt, die die Verkettung einer beliebigen Anzahl von Sequenzen enthält.

11

position

Es nimmt ein Element und eine Sequenz und gibt den Index des Elements in der Sequenz oder Null zurück.

12

find

Es braucht einen Gegenstand und eine Sequenz. Es findet das Element in der Sequenz und gibt es zurück. Wenn es nicht gefunden wird, gibt es null zurück.

13

sort

Es verwendet eine Sequenz und ein Prädikat mit zwei Argumenten und gibt eine sortierte Version der Sequenz zurück.

14

merge

Es werden zwei Sequenzen und ein Prädikat verwendet und eine Sequenz zurückgegeben, die durch Zusammenführen der beiden Sequenzen gemäß dem Prädikat erzeugt wird.

15

map

Es verwendet eine n-Argument-Funktion und n Sequenzen und gibt eine neue Sequenz zurück, die das Ergebnis der Anwendung der Funktion auf nachfolgende Elemente der Sequenzen enthält.

16

some

Es nimmt ein Prädikat als Argument und iteriert über die Argumentsequenz und gibt den ersten vom Prädikat zurückgegebenen Nicht-NIL-Wert zurück oder gibt false zurück, wenn das Prädikat niemals erfüllt ist.

17

every

Es nimmt ein Prädikat als Argument und iteriert über die Argumentsequenz. Es wird beendet und gibt false zurück, sobald das Prädikat fehlschlägt. Wenn das Prädikat immer erfüllt ist, gibt es true zurück.

18

notany

Es nimmt ein Prädikat als Argument und iteriert über die Argumentsequenz und gibt false zurück, sobald das Prädikat erfüllt oder wahr ist, wenn dies niemals der Fall ist.

19

notevery

Es nimmt ein Prädikat als Argument und iteriert über die Argumentsequenz und gibt true zurück, sobald das Prädikat fehlschlägt, oder false, wenn das Prädikat immer erfüllt ist.

20

reduce

Es wird einer einzelnen Sequenz zugeordnet, wobei eine Funktion mit zwei Argumenten zuerst auf die ersten beiden Elemente der Sequenz und dann auf den von der Funktion und den nachfolgenden Elementen der Sequenz zurückgegebenen Wert angewendet wird.

21

search

Es durchsucht eine Sequenz, um ein oder mehrere Elemente zu finden, die einen Test erfüllen.

22

remove

Es nimmt ein Element und eine Sequenz und gibt die Sequenz mit entfernten Instanzen des Elements zurück.

23

delete

Dies nimmt auch ein Element und eine Sequenz und gibt eine Sequenz der gleichen Art wie die Argumentsequenz zurück, die mit Ausnahme des Elements dieselben Elemente enthält.

24

substitute

Es nimmt ein neues Element, ein vorhandenes Element und eine Sequenz und gibt eine Sequenz zurück, bei der Instanzen des vorhandenen Elements durch das neue Element ersetzt werden.

25

nsubstitute

Es nimmt ein neues Element, ein vorhandenes Element und eine Sequenz und gibt dieselbe Sequenz zurück, wobei Instanzen des vorhandenen Elements durch das neue Element ersetzt werden.

26

mismatch

Es dauert zwei Sequenzen und gibt den Index des ersten Paares nicht übereinstimmender Elemente zurück.

Standard-Sequenzfunktion-Schlüsselwortargumente

Streit Bedeutung Standardwert
:Prüfung Es ist eine Funktion mit zwei Argumenten, mit der ein Element (oder ein Wert, der durch die Schlüsselfunktion extrahiert wurde) mit einem Element verglichen wird. EQL
:Schlüssel Ein-Argument-Funktion zum Extrahieren des Schlüsselwerts aus dem tatsächlichen Sequenzelement. NIL bedeutet, Element so wie es ist zu verwenden. NULL
:Start Startindex (einschließlich) der Teilsequenz. 0
:Ende Endindex (exklusiv) der Teilsequenz. NIL zeigt das Ende der Sequenz an. NULL
: von Ende Wenn true, wird die Sequenz von Ende bis Anfang in umgekehrter Reihenfolge durchlaufen. NULL
:Anzahl Nummer, die die Anzahl der zu entfernenden oder zu ersetzenden Elemente angibt, oder NIL, um alle anzugeben (nur ENTFERNEN und ERSETZEN). NULL

Wir haben gerade verschiedene Funktionen und Schlüsselwörter besprochen, die als Argumente in diesen Funktionen verwendet werden, die an Sequenzen arbeiten. In den nächsten Abschnitten werden wir anhand von Beispielen sehen, wie diese Funktionen verwendet werden.

Länge und Element finden

Das length Funktion gibt die Länge einer Sequenz zurück und die elt Mit dieser Funktion können Sie über einen ganzzahligen Index auf einzelne Elemente zugreifen.

Beispiel

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(setq x (vector 'a 'b 'c 'd 'e))
(write (length x))
(terpri)
(write (elt x 3))

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

5
D

Sequenzen ändern

Einige Sequenzfunktionen ermöglichen das Durchlaufen der Sequenz und das Ausführen einiger Operationen wie Suchen, Entfernen, Zählen oder Filtern bestimmter Elemente, ohne explizite Schleifen zu schreiben.

Das folgende Beispiel zeigt dies -

Beispiel 1

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(write (count 7 '(1 5 6 7 8 9 2 7 3 4 5)))
(terpri)
(write (remove 5 '(1 5 6 7 8 9 2 7 3 4 5)))
(terpri)
(write (delete 5 '(1 5 6 7 8 9 2 7 3 4 5)))
(terpri)
(write (substitute 10 7 '(1 5 6 7 8 9 2 7 3 4 5)))
(terpri)
(write (find 7 '(1 5 6 7 8 9 2 7 3 4 5)))
(terpri)
(write (position 5 '(1 5 6 7 8 9 2 7 3 4 5)))

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

2
(1 6 7 8 9 2 7 3 4)
(1 6 7 8 9 2 7 3 4)
(1 5 6 10 8 9 2 10 3 4 5)
7
1

Beispiel 2

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(write (delete-if #'oddp '(1 5 6 7 8 9 2 7 3 4 5)))
(terpri)
(write (delete-if #'evenp '(1 5 6 7 8 9 2 7 3 4 5)))
(terpri)
(write (remove-if #'evenp '(1 5 6 7 8 9 2 7 3 4 5) :count 1 :from-end t))
(terpri)
(setq x (vector 'a 'b 'c 'd 'e 'f 'g))
(fill x 'p :start 1 :end 4)
(write x)

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

(6 8 2 4)
(1 5 7 9 7 3 5)
(1 5 6 7 8 9 2 7 3 5)
#(A P P P E F G)

Sortieren und Zusammenführen von Sequenzen

Die Sortierfunktionen verwenden eine Sequenz und ein Prädikat mit zwei Argumenten und geben eine sortierte Version der Sequenz zurück.

Beispiel 1

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(write (sort '(2 4 7 3 9 1 5 4 6 3 8) #'<))
(terpri)
(write (sort '(2 4 7 3 9 1 5 4 6 3 8) #'>))
(terpri)

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

(1 2 3 3 4 4 5 6 7 8 9)
(9 8 7 6 5 4 4 3 3 2 1)

Beispiel 2

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(write (merge 'vector #(1 3 5) #(2 4 6) #'<))
(terpri)
(write (merge 'list #(1 3 5) #(2 4 6) #'<))
(terpri)

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

#(1 2 3 4 5 6)
(1 2 3 4 5 6)

Sequenzprädikate

Die Funktionen Every, Some, Notany und Notevery werden als Sequenzprädikate bezeichnet.

Diese Funktionen durchlaufen Sequenzen und testen das Boolesche Prädikat.

Alle diese Funktionen verwenden ein Prädikat als erstes Argument und die verbleibenden Argumente sind Sequenzen.

Beispiel

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(write (every #'evenp #(2 4 6 8 10)))
(terpri)
(write (some #'evenp #(2 4 6 8 10 13 14)))
(terpri)
(write (every #'evenp #(2 4 6 8 10 13 14)))
(terpri)
(write (notany #'evenp #(2 4 6 8 10)))
(terpri)
(write (notevery #'evenp #(2 4 6 8 10 13 14)))
(terpri)

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

T
T
NIL
NIL
T

Zuordnungssequenzen

Wir haben die Mapping-Funktionen bereits besprochen. Ebenso diemap Mit dieser Funktion können Sie eine Funktion auf nachfolgende Elemente einer oder mehrerer Sequenzen anwenden.

Das map Die Funktion verwendet eine Funktion mit n Argumenten und n Sequenzen und gibt eine neue Sequenz zurück, nachdem die Funktion auf nachfolgende Elemente der Sequenzen angewendet wurde.

Beispiel

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(write (map 'vector #'* #(2 3 4 5) #(3 5 4 8)))

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

#(6 15 16 40)

Listen waren die wichtigste und wichtigste zusammengesetzte Datenstruktur im traditionellen LISP. Das heutige Common LISP bietet andere Datenstrukturen wie Vektor, Hash-Tabelle, Klassen oder Strukturen.

Listen sind einzelne verknüpfte Listen. In LISP werden Listen als Kette einer einfachen Datensatzstruktur mit dem Namen erstelltcons miteinander verbunden.

Die Nachteile Datensatzstruktur

EIN cons ist eine Datensatzstruktur, die zwei Komponenten enthält, die als car und die cdr.

Nachteile Zellen oder Nachteile sind Objekte sind Wertepaare, die mit der Funktion erstellt werden cons.

Das consDie Funktion akzeptiert zwei Argumente und gibt eine neue Cons-Zelle zurück, die die beiden Werte enthält. Diese Werte können Verweise auf jede Art von Objekt sein.

Wenn der zweite Wert nicht Null oder eine andere Nachteilezelle ist, werden die Werte als gepunktetes Paar gedruckt, das in Klammern eingeschlossen ist.

Die beiden Werte in einer Cons-Zelle werden als bezeichnet car und die cdr. Das car Funktion wird verwendet, um auf den ersten Wert und die zuzugreifen cdr Funktion wird verwendet, um auf den zweiten Wert zuzugreifen.

Beispiel

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(write (cons 1 2))
(terpri)
(write (cons 'a 'b))
(terpri)
(write (cons 1 nil))
(terpri)
(write (cons 1 (cons 2 nil)))
(terpri)
(write (cons 1 (cons 2 (cons 3 nil))))
(terpri)
(write (cons 'a (cons 'b (cons 'c nil))))
(terpri)
(write ( car (cons 'a (cons 'b (cons 'c nil)))))
(terpri)
(write ( cdr (cons 'a (cons 'b (cons 'c nil)))))

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

(1 . 2)
(A . B)
(1)
(1 2)
(1 2 3)
(A B C)
A
(B C)

Das obige Beispiel zeigt, wie die Nachteile-Strukturen verwendet werden können, um eine einzelne verknüpfte Liste zu erstellen, z. B. besteht die Liste (ABC) aus drei Nachteile-Zellen, die durch ihre CDRs miteinander verbunden sind .

Diagrammatisch könnte es ausgedrückt werden als -

Listen in LISP

Obwohl Cons-Zellen zum Erstellen von Listen verwendet werden können, wird eine Liste aus verschachtelten Listen erstellt consFunktionsaufrufe können nicht die beste Lösung sein. Daslist Die Funktion wird eher zum Erstellen von Listen in LISP verwendet.

Die Listenfunktion kann eine beliebige Anzahl von Argumenten annehmen und wertet als Argument ihre Argumente aus.

Das first und restFunktionen geben das erste Element und den Rest einer Liste an. Die folgenden Beispiele veranschaulichen die Konzepte.

Beispiel 1

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(write (list 1 2))
(terpri)
(write (list 'a 'b))
(terpri)
(write (list 1 nil))
(terpri)
(write (list 1 2 3))
(terpri)
(write (list 'a 'b 'c))
(terpri)
(write (list 3 4 'a (car '(b . c)) (* 4 -2)))
(terpri)
(write (list (list 'a 'b) (list 'c 'd 'e)))

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

(1 2)
(A B)
(1 NIL)
(1 2 3)
(A B C)
(3 4 A B -8)
((A B) (C D E))

Beispiel 2

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(defun my-library (title author rating availability)
   (list :title title :author author :rating rating :availabilty availability)
)

(write (getf (my-library "Hunger Game" "Collins" 9 t) :title))

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

"Hunger Game"

Listenmanipulationsfunktionen

Die folgende Tabelle enthält einige häufig verwendete Funktionen zur Listenbearbeitung.

Sr.Nr. Bedienungsanleitung
1

car

Es nimmt eine Liste als Argument und gibt das erste Element zurück.

2

cdr

Es nimmt eine Liste als Argument und gibt eine Liste ohne das erste Element zurück

3

cons

Es werden zwei Argumente verwendet, ein Element und eine Liste, und es wird eine Liste zurückgegeben, in der das Element an erster Stelle eingefügt wird.

4

list

Es akzeptiert eine beliebige Anzahl von Argumenten und gibt eine Liste mit den Argumenten als Elementelemente der Liste zurück.

5

append

Es werden zwei oder mehr Listen zu einer zusammengeführt.

6

last

Es nimmt eine Liste und gibt eine Liste zurück, die das letzte Element enthält.

7

member

Es werden zwei Argumente benötigt, von denen das zweite eine Liste sein muss, wenn das erste Argument Mitglied des zweiten Arguments ist, und dann wird der Rest der Liste beginnend mit dem ersten Argument zurückgegeben.

8

reverse

Es nimmt eine Liste und gibt eine Liste mit den obersten Elementen in umgekehrter Reihenfolge zurück.

Bitte beachten Sie, dass alle Sequenzfunktionen auf Listen anwendbar sind.

Beispiel 3

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(write (car '(a b c d e f)))
(terpri)
(write (cdr '(a b c d e f)))
(terpri)
(write (cons 'a '(b c)))
(terpri)
(write (list 'a '(b c) '(e f)))
(terpri)
(write (append '(b c) '(e f) '(p q) '() '(g)))
(terpri)
(write (last '(a b c d (e f))))
(terpri)
(write (reverse '(a b c d (e f))))

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

A
(B C D E F)
(A B C)
(A (B C) (E F))
(B C E F P Q G)
((E F))
((E F) D C B A)

Verkettung von Auto- und CDR-Funktionen

Das car und cdr Funktionen und ihre Kombination ermöglichen das Extrahieren eines bestimmten Elements / Mitglieds einer Liste.

Sequenzen von Auto- und CDR-Funktionen könnten jedoch durch Verketten des Buchstabens a für Auto und d für CDR innerhalb der Buchstaben c und r abgekürzt werden.

Zum Beispiel können wir cadadr schreiben, um die Reihenfolge der Funktionsaufrufe abzukürzen - car cdr car cdr.

Somit gibt (cadadr '(a (cd) (efg))) d zurück

Beispiel 4

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(write (cadadr '(a (c d) (e f g))))
(terpri)
(write (caar (list (list 'a 'b) 'c)))   
(terpri)
(write (cadr (list (list 1 2) (list 3 4))))
(terpri)

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

D
A
(3 4)

In LISP ist ein Symbol ein Name, der Datenobjekte darstellt, und interessanterweise auch ein Datenobjekt.

Das Besondere an Symbolen ist, dass sie eine Komponente namens haben property list, oder plist.

Immobilienlisten

Mit LISP können Sie Symbolen Eigenschaften zuweisen. Lassen Sie uns zum Beispiel ein 'Personen'-Objekt haben. Wir möchten, dass dieses 'Personen'-Objekt Eigenschaften wie Name, Geschlecht, Größe, Gewicht, Adresse, Beruf usw. hat. Eine Eigenschaft ist wie ein Attributname.

Eine Eigenschaftsliste wird als Liste mit einer geraden Anzahl (möglicherweise Null) von Elementen implementiert. Jedes Elementpaar in der Liste bildet einen Eintrag. Der erste Punkt ist derindicator, und der zweite ist der value.

Wenn ein Symbol erstellt wird, ist seine Eigenschaftsliste zunächst leer. Eigenschaften werden mit erstelltget innerhalb eines setf bilden.

Mit den folgenden Anweisungen können wir beispielsweise einem Objekt mit dem Namen (Symbol) "Buch" den Titel, den Autor und den Herausgeber der Eigenschaften sowie die entsprechenden Werte zuweisen.

Beispiel 1

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(write (setf (get 'books'title) '(Gone with the Wind)))
(terpri)
(write (setf (get 'books 'author) '(Margaret Michel)))
(terpri)
(write (setf (get 'books 'publisher) '(Warner Books)))

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

(GONE WITH THE WIND)
(MARGARET MICHEL)
(WARNER BOOKS)

Mit verschiedenen Funktionen der Eigenschaftsliste können Sie Eigenschaften zuweisen sowie die Eigenschaften eines Symbols abrufen, ersetzen oder entfernen.

Das getDie Funktion gibt die Eigenschaftsliste des Symbols für einen bestimmten Indikator zurück. Es hat die folgende Syntax -

get symbol indicator &optional default

Das getDie Funktion sucht nach der Eigenschaftsliste des angegebenen Symbols für den angegebenen Indikator. Wenn sie gefunden wird, gibt sie den entsprechenden Wert zurück. Andernfalls wird default zurückgegeben (oder nil, wenn kein Standardwert angegeben ist).

Beispiel 2

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(setf (get 'books 'title) '(Gone with the Wind))
(setf (get 'books 'author) '(Margaret Micheal))
(setf (get 'books 'publisher) '(Warner Books))

(write (get 'books 'title))
(terpri)
(write (get 'books 'author))
(terpri)
(write (get 'books 'publisher))

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

(GONE WITH THE WIND)
(MARGARET MICHEAL)
(WARNER BOOKS)

Das symbol-plist Mit dieser Funktion können Sie alle Eigenschaften eines Symbols anzeigen.

Beispiel 3

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(setf (get 'annie 'age) 43)
(setf (get 'annie 'job) 'accountant)
(setf (get 'annie 'sex) 'female)
(setf (get 'annie 'children) 3)

(terpri)
(write (symbol-plist 'annie))

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

(CHILDREN 3 SEX FEMALE JOB ACCOUNTANT AGE 43)

Das remprop Funktion entfernt die angegebene Eigenschaft aus einem Symbol.

Beispiel 4

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(setf (get 'annie 'age) 43)
(setf (get 'annie 'job) 'accountant)
(setf (get 'annie 'sex) 'female)
(setf (get 'annie 'children) 3)

(terpri)
(write (symbol-plist 'annie))
(remprop 'annie 'age)
(terpri)
(write (symbol-plist 'annie))

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

(CHILDREN 3 SEX FEMALE JOB ACCOUNTANT AGE 43)
(CHILDREN 3 SEX FEMALE JOB ACCOUNTANT)

Vektoren sind eindimensionale Arrays, daher ein Subtyp eines Arrays. Vektoren und Listen werden gemeinsam als Sequenzen bezeichnet. Daher arbeiten alle bisher diskutierten generischen Sequenzfunktionen und Array-Funktionen an Vektoren.

Vektoren erstellen

Mit der Vektorfunktion können Sie Vektoren fester Größe mit bestimmten Werten erstellen. Es akzeptiert eine beliebige Anzahl von Argumenten und gibt einen Vektor zurück, der diese Argumente enthält.

Beispiel 1

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(setf v1 (vector 1 2 3 4 5))
(setf v2 #(a b c d e))
(setf v3 (vector 'p 'q 'r 's 't))

(write v1)
(terpri)
(write v2)
(terpri)
(write v3)

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

#(1 2 3 4 5)
#(A B C D E)
#(P Q R S T)

Bitte beachten Sie, dass LISP die Syntax # (...) als Literalnotation für Vektoren verwendet. Mit dieser Syntax # (...) können Sie Literalvektoren erstellen und in Ihren Code aufnehmen.

Dies sind jedoch Literalvektoren, sodass das Ändern dieser Vektoren in LISP nicht definiert ist. Daher sollten Sie für die Programmierung immer die verwendenvector Funktion oder die allgemeinere Funktion make-array um Vektoren zu erstellen, die Sie ändern möchten.

Das make-arrayFunktion ist die allgemeinere Methode zum Erstellen eines Vektors. Sie können auf die Vektorelemente mit dem zugreifenaref Funktion.

Beispiel 2

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(setq a (make-array 5 :initial-element 0))
(setq b (make-array 5 :initial-element 2))

(dotimes (i 5)
   (setf (aref a i) i))
   
(write a)
(terpri)
(write b)
(terpri)

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

#(0 1 2 3 4)
#(2 2 2 2 2)

Zeiger füllen

Das make-array Mit dieser Funktion können Sie einen veränderbaren Vektor erstellen.

Das fill-pointerDas Argument der Funktion verfolgt die Anzahl der tatsächlich im Vektor gespeicherten Elemente. Dies ist der Index der nächsten Position, die gefüllt werden muss, wenn Sie dem Vektor ein Element hinzufügen.

Das vector-pushMit dieser Funktion können Sie ein Element am Ende eines veränderbaren Vektors hinzufügen. Es erhöht den Füllzeiger um 1.

Das vector-pop Die Funktion gibt das zuletzt gepusste Element zurück und dekrementiert den Füllzeiger um 1.

Beispiel

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(setq a (make-array 5 :fill-pointer 0))
(write a)

(vector-push 'a a)
(vector-push 'b a)
(vector-push 'c a)

(terpri)
(write a)
(terpri)

(vector-push 'd a)
(vector-push 'e a)

;this will not be entered as the vector limit is 5
(vector-push 'f a)

(write a)
(terpri)

(vector-pop a)
(vector-pop a)
(vector-pop a)

(write a)

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

#()
#(A B C)
#(A B C D E)
#(A B)

Da Vektoren Sequenzen sind, sind alle Sequenzfunktionen für Vektoren anwendbar. Informationen zu Vektorfunktionen finden Sie im Kapitel Sequenzen.

Common Lisp bietet keinen festgelegten Datentyp. Es bietet jedoch eine Reihe von Funktionen, mit denen festgelegte Operationen für eine Liste ausgeführt werden können.

Sie können Elemente in einer Liste basierend auf verschiedenen Kriterien hinzufügen, entfernen und suchen. Sie können auch verschiedene Mengenoperationen ausführen, z. B. Vereinigung, Schnittpunkt und Mengenunterschied.

Implementieren von Sets in LISP

Mengen wie Listen werden im Allgemeinen in Form von Nachteilezellen implementiert. Aus diesem Grund werden die Mengenoperationen jedoch immer weniger effizient, je größer die Mengen werden.

Das adjoinMit dieser Funktion können Sie ein Set aufbauen. Es werden ein Element und eine Liste, die eine Menge darstellen, verwendet und eine Liste zurückgegeben, die die Gruppe darstellt, die das Element und alle Elemente in der ursprünglichen Gruppe enthält.

Das adjoinDie Funktion sucht zuerst nach dem Element in der angegebenen Liste. Wenn es gefunden wird, gibt sie die ursprüngliche Liste zurück. andernfalls erstellt es mit seiner eine neue Nachteile-Zellecar als Gegenstand und cdr zeigt auf die ursprüngliche Liste und gibt diese neue Liste zurück.

Das adjoin Funktion dauert auch :key und :testSchlüsselwortargumente. Diese Argumente werden verwendet, um zu überprüfen, ob das Element in der ursprünglichen Liste vorhanden ist.

Da die Adjoin-Funktion die ursprüngliche Liste nicht ändert, müssen Sie entweder den von adjoin zurückgegebenen Wert der ursprünglichen Liste zuweisen oder das Makro verwenden, um eine Änderung an der Liste selbst vorzunehmen pushnew um ein Element zum Set hinzuzufügen.

Beispiel

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

; creating myset as an empty list
(defparameter *myset* ())
(adjoin 1 *myset*)
(adjoin 2 *myset*)

; adjoin did not change the original set
;so it remains same
(write *myset*)
(terpri)
(setf *myset* (adjoin 1 *myset*))
(setf *myset* (adjoin 2 *myset*))

;now the original set is changed
(write *myset*)
(terpri)

;adding an existing value
(pushnew 2 *myset*)

;no duplicate allowed
(write *myset*)
(terpri)

;pushing a new value
(pushnew 3 *myset*)
(write *myset*)
(terpri)

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

NIL
(2 1)
(2 1)
(3 2 1)

Überprüfung der Mitgliedschaft

Mit der Elementfunktionsgruppe können Sie überprüfen, ob ein Element Mitglied einer Gruppe ist oder nicht.

Im Folgenden sind die Syntaxen dieser Funktionen aufgeführt:

member item list &key :test :test-not :key 
member-if predicate list &key :key 
member-if-not predicate list &key :key

Diese Funktionen durchsuchen die angegebene Liste nach einem bestimmten Element, das den Test erfüllt. Wird kein solches Element gefunden, werden die Funktionen zurückgegebennil. Andernfalls wird das Ende der Liste mit dem Element als erstem Element zurückgegeben.

Die Suche wird nur auf der obersten Ebene durchgeführt.

Diese Funktionen könnten als Prädikate verwendet werden.

Beispiel

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(write (member 'zara '(ayan abdul zara riyan nuha)))
(terpri)
(write (member-if #'evenp '(3 7 2 5/3 'a)))
(terpri)
(write (member-if-not #'numberp '(3 7 2 5/3 'a 'b 'c)))

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

(ZARA RIYAN NUHA)
(2 5/3 'A)
('A 'B 'C)

Set Union

Mit der Union-Funktionsgruppe können Sie eine Set-Union für zwei Listen durchführen, die als Argumente für diese Funktionen auf der Grundlage eines Tests bereitgestellt werden.

Im Folgenden sind die Syntaxen dieser Funktionen aufgeführt:

union list1 list2 &key :test :test-not :key 
nunion list1 list2 &key :test :test-not :key

Das unionDie Funktion verwendet zwei Listen und gibt eine neue Liste zurück, die alle in einer der Listen vorhandenen Elemente enthält. Wenn es Duplikate gibt, wird nur eine Kopie des Mitglieds in der zurückgegebenen Liste gespeichert.

Das nunion Die Funktion führt dieselbe Operation aus, kann jedoch die Argumentlisten zerstören.

Beispiel

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(setq set1 (union '(a b c) '(c d e)))
(setq set2 (union '(#(a b) #(5 6 7) #(f h)) 
   '(#(5 6 7) #(a b) #(g h)) :test-not #'mismatch)
)
       
(setq set3 (union '(#(a b) #(5 6 7) #(f h)) 
   '(#(5 6 7) #(a b) #(g h)))
)
(write set1)
(terpri)
(write set2)
(terpri)
(write set3)

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

(A B C D E)
(#(F H) #(5 6 7) #(A B) #(G H))
(#(A B) #(5 6 7) #(F H) #(5 6 7) #(A B) #(G H))

Bitte beachten Sie

Die Gewerkschaftsfunktion funktioniert ohne nicht wie erwartet :test-not #'mismatchArgumente für eine Liste von drei Vektoren. Dies liegt daran, dass die Listen aus Nachteile bestehen und obwohl die Werte für uns anscheinend gleich aussehen, diecdrEin Teil der Zellen stimmt nicht überein, daher sind sie nicht genau mit dem LISP-Interpreter / Compiler identisch. Das ist der Grund; Das Implementieren großer Mengen wird nicht empfohlen, Listen zu verwenden. Es funktioniert jedoch gut für kleine Sets.

Schnittpunkt einstellen

Mit der Schnittpunktfunktionsgruppe können Sie auf der Grundlage eines Tests eine Schnittmenge für zwei Listen durchführen, die als Argumente für diese Funktionen bereitgestellt werden.

Im Folgenden sind die Syntaxen dieser Funktionen aufgeführt:

intersection list1 list2 &key :test :test-not :key 
nintersection list1 list2 &key :test :test-not :key

Diese Funktionen verwenden zwei Listen und geben eine neue Liste zurück, die alle in beiden Argumentlisten enthaltenen Elemente enthält. Wenn eine der Listen doppelte Einträge enthält, werden die redundanten Einträge möglicherweise im Ergebnis angezeigt oder nicht.

Beispiel

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(setq set1 (intersection '(a b c) '(c d e)))
(setq set2 (intersection '(#(a b) #(5 6 7) #(f h)) 
   '(#(5 6 7) #(a b) #(g h)) :test-not #'mismatch)
)
       
(setq set3 (intersection '(#(a b) #(5 6 7) #(f h)) 
   '(#(5 6 7) #(a b) #(g h)))
)
(write set1)
(terpri)
(write set2)
(terpri)
(write set3)

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

(C)
(#(A B) #(5 6 7))
NIL

Die Schnittfunktion ist die destruktive Version der Kreuzung, dh sie kann die ursprünglichen Listen zerstören.

Differenz einstellen

Mit der Set-Difference-Funktionsgruppe können Sie Set-Difference für zwei Listen ausführen, die als Argumente für diese Funktionen auf der Grundlage eines Tests bereitgestellt werden.

Im Folgenden sind die Syntaxen dieser Funktionen aufgeführt:

set-difference list1 list2 &key :test :test-not :key 
nset-difference list1 list2 &key :test :test-not :key

Die Set-Difference-Funktion gibt eine Liste der Elemente der ersten Liste zurück, die nicht in der zweiten Liste enthalten sind.

Beispiel

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(setq set1 (set-difference '(a b c) '(c d e)))
(setq set2 (set-difference '(#(a b) #(5 6 7) #(f h)) 
   '(#(5 6 7) #(a b) #(g h)) :test-not #'mismatch)
)
(setq set3 (set-difference '(#(a b) #(5 6 7) #(f h)) 
   '(#(5 6 7) #(a b) #(g h)))
)
(write set1)
(terpri)
(write set2)
(terpri)
(write set3)

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

(A B)
(#(F H))
(#(A B) #(5 6 7) #(F H))

Sie können Baumdatenstrukturen aus Nachteilezellen als Listen von Listen erstellen.

Um Baumstrukturen zu implementieren, müssen Sie Funktionen entwerfen, die die Nachteile-Zellen in einer bestimmten Reihenfolge durchlaufen, z. B. in der Reihenfolge vor, in der Reihenfolge und nach der Reihenfolge für Binärbäume.

Baum als Listenliste

Betrachten wir eine Baumstruktur aus Cons-Zellen, die die folgende Liste von Listen bilden:

((1 2) (3 4) (5 6)).

Diagrammatisch könnte es ausgedrückt werden als -

Baumfunktionen in LISP

Obwohl Sie meistens Ihre eigenen Baumfunktionen entsprechend Ihren spezifischen Anforderungen schreiben müssen, bietet LISP einige Baumfunktionen, die Sie verwenden können.

Abgesehen von allen Listenfunktionen funktionieren die folgenden Funktionen insbesondere für Baumstrukturen:

Sr.Nr. Bedienungsanleitung
1

copy-tree x & optional vecp

Es wird eine Kopie des Baums der Nachteile x zurückgegeben. Es kopiert rekursiv sowohl die Auto- als auch die CDR-Richtung. Wenn x keine Nachteilezelle ist, gibt die Funktion x einfach unverändert zurück. Wenn das optionale vecp-Argument wahr ist, kopiert diese Funktion sowohl Vektoren (rekursiv) als auch Nachteile-Zellen.

2

tree-equal xy & key: test: test-not: key

Es vergleicht zwei Bäume von Nachteile-Zellen. Wenn x und y beide Nachteile sind, werden ihre Autos und CDs rekursiv verglichen. Wenn weder x noch y eine Nachteilezelle sind, werden sie nach Gleichung oder gemäß dem angegebenen Test verglichen. Die Funktion: key wird, falls angegeben, auf die Elemente beider Bäume angewendet.

3

subst neuer alter Baum & Schlüssel: Test: Test-nicht: Schlüssel

Es ersetzt das Auftreten eines bestimmten alten Elements durch ein neues Element im Baum , der ein Baum von Nachteilezellen ist.

4

nsubst neuer alter Baum & Schlüssel: Test: Test-nicht: Schlüssel

Es funktioniert genauso wie subst, zerstört jedoch den ursprünglichen Baum.

5

sublis Alist Tree & Key: Test: Test-Not: Key

Es funktioniert wie subst, außer dass eine Zuordnungsliste mit alten und neuen Paaren erstellt wird. Jedes Element des Baums (nach Anwendung der Funktion: key, falls vorhanden) wird mit den Autos von alist verglichen. Wenn es übereinstimmt, wird es durch die entsprechende CDR ersetzt.

6

nsublis Alist Tree & Key: Test: Test-Not: Key

Es funktioniert genauso wie Sublis, ist jedoch eine destruktive Version.

Beispiel 1

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(setq lst (list '(1 2) '(3 4) '(5 6)))
(setq mylst (copy-list lst))
(setq tr (copy-tree lst))

(write lst)
(terpri)
(write mylst)
(terpri)
(write tr)

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

((1 2) (3 4) (5 6))
((1 2) (3 4) (5 6))
((1 2) (3 4) (5 6))

Beispiel 2

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(setq tr '((1 2 (3 4 5) ((7 8) (7 8 9)))))
(write tr)
(setq trs (subst 7 1 tr))
(terpri)
(write trs)

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

((1 2 (3 4 5) ((7 8) (7 8 9))))
((7 2 (3 4 5) ((7 8) (7 8 9))))

Bauen Sie Ihren eigenen Baum

Versuchen wir, mithilfe der in LISP verfügbaren Listenfunktionen einen eigenen Baum zu erstellen.

Lassen Sie uns zunächst einen neuen Knoten erstellen, der einige Daten enthält

(defun make-tree (item)
   "it creates a new node with item."
   (cons (cons item nil) nil)
)

Als nächstes fügen wir dem Baum einen untergeordneten Knoten hinzu - es werden zwei Baumknoten benötigt und der zweite Baum als untergeordnetes Element des ersten Baums hinzugefügt.

(defun add-child (tree child)
   (setf (car tree) (append (car tree) child))
   tree)

Diese Funktion gibt dem ersten Kind einen bestimmten Baum zurück - sie nimmt einen Baumknoten und gibt das erste Kind dieses Knotens zurück, oder null, wenn dieser Knoten keinen untergeordneten Knoten hat.

(defun first-child (tree)
   (if (null tree)
      nil
      (cdr (car tree))
   )
)

Diese Funktion gibt das nächste Geschwister eines bestimmten Knotens zurück - sie verwendet einen Baumknoten als Argument und gibt einen Verweis auf den nächsten Geschwisterknoten oder null zurück, wenn der Knoten keinen hat.

(defun next-sibling (tree)
   (cdr tree)
)

Zuletzt benötigen wir eine Funktion, um die Informationen in einem Knoten zurückzugeben -

(defun data (tree)
   (car (car tree))
)

Beispiel

In diesem Beispiel werden die oben genannten Funktionen verwendet -

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(defun make-tree (item)
   "it creates a new node with item."
   (cons (cons item nil) nil)
)
(defun first-child (tree)
   (if (null tree)
      nil
      (cdr (car tree))
   )
)

(defun next-sibling (tree)
   (cdr tree)
)
(defun data (tree)
   (car (car tree))
)
(defun add-child (tree child)
   (setf (car tree) (append (car tree) child))
   tree
)

(setq tr '((1 2 (3 4 5) ((7 8) (7 8 9)))))
(setq mytree (make-tree 10))

(write (data mytree))
(terpri)
(write (first-child tr))
(terpri)
(setq newtree (add-child tr mytree))
(terpri)
(write newtree)

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

10
(2 (3 4 5) ((7 8) (7 8 9)))

((1 2 (3 4 5) ((7 8) (7 8 9)) (10)))

Die Datenstruktur der Hash-Tabelle repräsentiert eine Sammlung von key-and-valuePaare, die basierend auf dem Hash-Code des Schlüssels organisiert sind. Es verwendet den Schlüssel, um auf die Elemente in der Sammlung zuzugreifen.

Eine Hash-Tabelle wird verwendet, wenn Sie mithilfe eines Schlüssels auf Elemente zugreifen müssen, und Sie können einen nützlichen Schlüsselwert identifizieren. Jedes Element in der Hash-Tabelle hat ein Schlüssel / Wert-Paar. Der Schlüssel wird verwendet, um auf die Elemente in der Sammlung zuzugreifen.

Erstellen einer Hash-Tabelle in LISP

In Common LISP ist die Hash-Tabelle eine allgemeine Sammlung. Sie können beliebige Objekte als Schlüssel oder Index verwenden.

Wenn Sie einen Wert in einer Hash-Tabelle speichern, erstellen Sie ein Schlüssel-Wert-Paar und speichern es unter diesem Schlüssel. Später können Sie den Wert mit demselben Schlüssel aus der Hash-Tabelle abrufen. Jeder Schlüssel ist einem einzelnen Wert zugeordnet, obwohl Sie einen neuen Wert in einem Schlüssel speichern können.

Hash-Tabellen in LISP können basierend auf der Art und Weise, wie die Schlüssel verglichen werden können, in drei Typen eingeteilt werden - eq, eql oder gleich. Wenn die Hash-Tabelle für LISP-Objekte gehasht wird, werden die Schlüssel mit eq oder eql verglichen. Wenn die Hash-Tabelle in der Baumstruktur hasht, wird sie mit gleich verglichen.

Das make-hash-tableFunktion wird zum Erstellen einer Hash-Tabelle verwendet. Die Syntax für diese Funktion lautet -

make-hash-table &key :test :size :rehash-size :rehash-threshold

Wo -

  • Das key Argument liefert den Schlüssel.

  • Das :testDas Argument bestimmt, wie Schlüssel verglichen werden. Es sollte einen von drei Werten # 'eq, #' eql oder # 'gleich oder eines der drei Symbole eq, eql oder gleich haben. Wenn nicht angegeben, wird eql angenommen.

  • Das :sizeArgument legt die Anfangsgröße der Hash-Tabelle fest. Dies sollte eine ganze Zahl größer als Null sein.

  • Das :rehash-sizeDas Argument gibt an, um wie viel die Hash-Tabelle vergrößert werden soll, wenn sie voll ist. Dies kann eine Ganzzahl größer als Null sein, dh die Anzahl der hinzuzufügenden Einträge, oder eine Gleitkommazahl größer als 1, dh das Verhältnis der neuen Größe zur alten Größe. Der Standardwert für dieses Argument ist implementierungsabhängig.

  • Das :rehash-thresholdDas Argument gibt an, wie voll die Hash-Tabelle werden kann, bevor sie wachsen muss. Dies kann eine Ganzzahl sein, die größer als Null und kleiner als die: Rehash-Größe ist (in diesem Fall wird sie skaliert, wenn die Tabelle vergrößert wird), oder es kann eine Gleitkommazahl zwischen Null und 1 sein. Der Standardwert hierfür Argument ist implementierungsabhängig.

Sie können die Funktion make-hash-table auch ohne Argumente aufrufen.

Abrufen von Elementen aus und Hinzufügen von Elementen zur Hash-Tabelle

Das gethashDie Funktion ruft ein Element aus der Hash-Tabelle ab, indem sie nach seinem Schlüssel sucht. Wenn der Schlüssel nicht gefunden wird, wird null zurückgegeben.

Es hat die folgende Syntax -

gethash key hash-table &optional default

wo -

  • Schlüssel: ist der zugehörige Schlüssel

  • Hash-Tabelle: ist die zu durchsuchende Hash-Tabelle

  • Standard: ist der Wert, der zurückgegeben werden soll, wenn der Eintrag nicht gefunden wird. Wenn nicht angegeben, ist er null.

Das gethash Die Funktion gibt tatsächlich zwei Werte zurück, wobei der zweite ein Prädikatwert ist, der wahr ist, wenn ein Eintrag gefunden wurde, und falsch, wenn kein Eintrag gefunden wurde.

Zum Hinzufügen eines Elements zur Hash-Tabelle können Sie die verwenden setf Funktion zusammen mit dem gethash Funktion.

Beispiel

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(setq empList (make-hash-table)) 
(setf (gethash '001 empList) '(Charlie Brown))
(setf (gethash '002 empList) '(Freddie Seal)) 
(write (gethash '001 empList)) 
(terpri)
(write (gethash '002 empList))

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

(CHARLIE BROWN)
(FREDDIE SEAL)

Einen Eintrag entfernen

Das remhashDie Funktion entfernt alle Einträge für einen bestimmten Schlüssel in der Hash-Tabelle. Dies ist ein Prädikat, das wahr ist, wenn es einen Eintrag gab, oder falsch, wenn es keinen gab.

Die Syntax für diese Funktion lautet -

remhash key hash-table

Beispiel

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(setq empList (make-hash-table)) 
(setf (gethash '001 empList) '(Charlie Brown))
(setf (gethash '002 empList) '(Freddie Seal)) 
(setf (gethash '003 empList) '(Mark Mongoose)) 

(write (gethash '001 empList)) 
(terpri)
(write (gethash '002 empList)) 
(terpri)
(write (gethash '003 empList))  
(remhash '003 empList)
(terpri)
(write (gethash '003 empList))

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

(CHARLIE BROWN)
(FREDDIE SEAL)
(MARK MONGOOSE)
NIL

Die Maphash-Funktion

Das maphash Mit dieser Funktion können Sie eine bestimmte Funktion auf jedes Schlüssel-Wert-Paar in einer Hash-Tabelle anwenden.

Es werden zwei Argumente verwendet - die Funktion und eine Hash-Tabelle. Die Funktion wird einmal für jedes Schlüssel / Wert-Paar in der Hash-Tabelle aufgerufen.

Beispiel

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(setq empList (make-hash-table)) 
(setf (gethash '001 empList) '(Charlie Brown))
(setf (gethash '002 empList) '(Freddie Seal)) 
(setf (gethash '003 empList) '(Mark Mongoose)) 

(maphash #'(lambda (k v) (format t "~a => ~a~%" k v)) empList)

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

3 => (MARK MONGOOSE)
2 => (FREDDIE SEAL)
1 => (CHARLIE BROWN)

Common LISP bietet zahlreiche Eingabe-Ausgabe-Funktionen. Wir haben bereits die Formatierungsfunktion und die Druckfunktion für die Ausgabe verwendet. In diesem Abschnitt werden einige der am häufigsten verwendeten Eingabe-Ausgabe-Funktionen in LISP vorgestellt.

Eingabefunktionen

Die folgende Tabelle enthält die am häufigsten verwendeten Eingabefunktionen von LISP -

Sr.Nr. Bedienungsanleitung
1

read& optionaler Eingabestream eof-error-p eof-Wert rekursiv-p

Es liest die gedruckte Darstellung eines Lisp-Objekts aus dem Eingabestream ein, erstellt ein entsprechendes Lisp-Objekt und gibt das Objekt zurück.

2

read-preserving-whitespace& optionaler In-Stream eof-error-p eof-Wert rekursiv-p

Es wird in einigen speziellen Situationen verwendet, in denen es wünschenswert ist, genau zu bestimmen, welches Zeichen das erweiterte Token beendet hat.

3

read-line& optionaler Eingabestream eof-error-p eof-Wert rekursiv-p

Es liest eine Textzeile ein, die durch eine neue Zeile abgeschlossen ist.

4

read-char& optionaler Eingabestream eof-error-p eof-Wert rekursiv-p

Es nimmt ein Zeichen aus dem Eingabestream und gibt es als Zeichenobjekt zurück.

5

unread-char Zeichen & optionaler Eingabestream

Das zuletzt aus dem Eingabestream gelesene Zeichen wird auf die Vorderseite des Eingabestreams gesetzt.

6

peek-char& optionaler Peek-Typ-Eingabestream eof-error-p eof-value recursive-p

Es gibt das nächste Zeichen zurück, das aus dem Eingabestream gelesen werden soll, ohne es tatsächlich aus dem Eingabestream zu entfernen.

7

listen& optionaler Eingabestream

Das Prädikat listen ist wahr, wenn ein Zeichen sofort im Eingabestream verfügbar ist, und ist falsch, wenn nicht.

8

read-char-no-hang& optionaler Eingabestream eof-error-p eof-Wert rekursiv-p

Es ist ähnlich wie read-char, aber wenn es kein Zeichen bekommt, wartet es nicht auf ein Zeichen, sondern gibt sofort null zurück.

9

clear-input& optionaler Eingabestream

Es löscht alle gepufferten Eingaben, die dem Eingabestream zugeordnet sind.

10

read-from-string Zeichenfolge & optionaler eof-error-p eof-Wert & Schlüssel: Start: Ende: Erhalten-Leerzeichen

Es nimmt die Zeichen der Zeichenfolge nacheinander auf, erstellt ein LISP-Objekt und gibt das Objekt zurück. Es gibt auch den Index des ersten Zeichens in der nicht gelesenen Zeichenfolge oder die Länge der Zeichenfolge (oder gegebenenfalls die Länge +1) zurück.

11

parse-integer Zeichenfolge & Schlüssel: Start: Ende: Radix: Junk-erlaubt

Es wird die Teilzeichenfolge der Zeichenfolge untersucht, die durch: start und: end begrenzt ist (standardmäßig Anfang und Ende der Zeichenfolge). Es überspringt Leerzeichen und versucht dann, eine Ganzzahl zu analysieren.

12

read-byte Binär-Eingangsstrom & optional EOF-error-p EOF-Wert

Es liest ein Byte aus dem Binäreingabestream und gibt es in Form einer Ganzzahl zurück.

Eingabe von der Tastatur lesen

Das readDie Funktion dient zur Eingabe über die Tastatur. Es darf kein Argument sein.

Betrachten Sie zum Beispiel das Code-Snippet -

(write ( + 15.0 (read)))

Angenommen, der Benutzer gibt 10.2 über die STDIN-Eingabe ein.

25.2

Die Lesefunktion liest Zeichen aus einem Eingabestream und interpretiert sie durch Parsen als Darstellungen von Lisp-Objekten.

Beispiel

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein:

; the function AreaOfCircle
; calculates area of a circle
; when the radius is input from keyboard

(defun AreaOfCircle()
(terpri)
(princ "Enter Radius: ")
(setq radius (read))
(setq area (* 3.1416 radius radius))
(princ "Area: ")
(write area))
(AreaOfCircle)

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

Enter Radius: 5 (STDIN Input)
Area: 78.53999

Beispiel

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(with-input-from-string (stream "Welcome to Tutorials Point!")
   (print (read-char stream))
   (print (read-char stream))
   (print (read-char stream))
   (print (read-char stream))
   (print (read-char stream))
   (print (read-char stream))
   (print (read-char stream))
   (print (read-char stream))
   (print (read-char stream))
   (print (read-char stream))
   (print (peek-char nil stream nil 'the-end))
   (values)
)

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

#\W 
#\e 
#\l 
#\c 
#\o 
#\m 
#\e 
#\Space 
#\t 
#\o 
#\Space

Die Ausgabefunktionen

Alle Ausgabefunktionen in LISP verwenden ein optionales Argument namens Ausgabestream, an das die Ausgabe gesendet wird. Wenn nicht erwähnt oder null, wird für den Ausgabestream standardmäßig der Wert der Variablen * Standardausgabe * verwendet.

Die folgende Tabelle enthält die am häufigsten verwendeten Ausgabefunktionen von LISP -

Sr.Nr. Funktion und Beschreibung
1

write Objekt & Schlüssel: Stream: Escape: Radix: Basis: Kreis: Hübsch: Ebene: Länge: Fall: Gensym: Array

write Objekt & Schlüssel: Stream: Escape: Radix: Basis: Kreis: Hübsch: Ebene: Länge: Fall: Gensym: Array: Lesbar: Rechter Rand: Geizhalsbreite: Zeilen: Druckabzug

Beide schreiben das Objekt in den durch: stream angegebenen Ausgabestream, der standardmäßig den Wert * standard-output * verwendet. Andere Werte sind standardmäßig die entsprechenden globalen Variablen, die zum Drucken festgelegt wurden.

2

prin1 Objekt & optionaler Ausgabestream

print Objekt & optionaler Ausgabestream

pprint Objekt & optionaler Ausgabestream

princ Objekt & optionaler Ausgabestream

Alle diese Funktionen geben die gedruckte Darstellung des Objekts an den Ausgabestream aus . Es gibt jedoch die folgenden Unterschiede:

  • prin1 gibt das Objekt als Wert zurück.

  • print druckt das Objekt mit einer vorangestellten neuen Zeile und gefolgt von einem Leerzeichen. Es gibt ein Objekt zurück.

  • pprint ist genau wie print, nur dass der nachgestellte Leerzeichen weggelassen wird.

  • princ ist genau wie prin1, nur dass die Ausgabe kein Escapezeichen hat

3

write-to-string Objekt & Schlüssel : Escape: Radix: Basis: Kreis: Hübsch: Ebene: Länge: Fall: Gensym: Array

write-to-string Objekt & Schlüssel: Escape: Radix: Basis: Kreis: Hübsch: Ebene: Länge: Groß- / Kleinschreibung: Gensym: Array: Lesbar: Rechter Rand: Geizhals-Breite: Zeilen: Druck-Versand

prin1-to-string Objekt

princ-to-string Objekt

Das Objekt wird effektiv gedruckt und die Ausgabezeichen werden zu einer Zeichenfolge verarbeitet, die zurückgegeben wird.

4

write-char Zeichen & optionaler Ausgabestream

Es gibt das Zeichen an den Ausgabestream aus und gibt das Zeichen zurück.

5

write-string Zeichenfolge & optionaler Ausgabestream & Schlüssel: Start: Ende

Es schreibt die Zeichen des angegebenen Teilstrings der Zeichenfolge in den Ausgabestream.

6

write-line Zeichenfolge & optionaler Ausgabestream & Schlüssel: Start: Ende

Es funktioniert genauso wie Write-String, gibt danach jedoch eine neue Zeile aus.

7

terpri& optionaler Ausgabestream

Es gibt eine neue Zeile an den Ausgabestream aus.

8

fresh-line& optionaler Ausgabestream

Es wird nur dann eine neue Zeile ausgegeben, wenn sich der Stream noch nicht am Anfang einer Zeile befindet.

9

finish-output& optionaler Ausgabestream

force-output& optionaler Ausgabestream

clear-output& optionaler Ausgabestream

  • Die Funktion finish-output versucht sicherzustellen, dass alle an den Ausgabestream gesendeten Ausgaben ihr Ziel erreicht haben, und gibt erst dann null zurück.

  • Die Funktion force-output Initiiert das Entleeren aller internen Puffer, gibt jedoch Null zurück, ohne auf den Abschluss oder die Bestätigung zu warten.

  • Die Funktion clear-output Es wird versucht, eine ausstehende Ausgabeoperation abzubrechen, damit so wenig Ausgabe wie möglich zum Ziel weitergeleitet werden kann.

10

write-byte Integer-Binärausgangsstrom

Es schreibt ein Byte, den Wert der Ganzzahl.

Beispiel

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

; this program inputs a numbers and doubles it
(defun DoubleNumber()
   (terpri)
   (princ "Enter Number : ")
   (setq n1 (read))
   (setq doubled (* 2.0 n1))
   (princ "The Number: ")
   (write n1)
   (terpri)
   (princ "The Number Doubled: ")
   (write doubled)
)
(DoubleNumber)

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

Enter Number : 3456.78 (STDIN Input)
The Number: 3456.78
The Number Doubled: 6913.56

Formatierte Ausgabe

Die Funktion formatwird zum Erstellen von schön formatiertem Text verwendet. Es hat die folgende Syntax -

format destination control-string &rest arguments

wo,

  • Ziel ist Standardausgabe
  • Steuerzeichenfolge enthält die auszugebenden Zeichen und die Druckanweisung.

EIN format directive besteht aus einer Tilde (~), optionalen Präfixparametern, die durch Kommas getrennt sind, optionalen Modifikatoren für Doppelpunkte (:) und at-sign (@) sowie einem einzelnen Zeichen, das angibt, um welche Art von Direktive es sich handelt.

Die Präfixparameter sind im Allgemeinen Ganzzahlen, die als optional vorzeichenbehaftete Dezimalzahlen notiert werden.

Die folgende Tabelle enthält eine kurze Beschreibung der häufig verwendeten Richtlinien -

Sr.Nr. Richtlinie & Beschreibung
1

~A

Wird von ASCII-Argumenten gefolgt.

2

~S

Es folgen S-Ausdrücke.

3

~D

Für Dezimalargumente.

4

~B

Für binäre Argumente.

5

~O

Für oktale Argumente.

6

~X

Für hexadezimale Argumente.

7

~C

Für Zeichenargumente.

8

~F

Für Gleitkomma-Argumente mit festem Format.

9

~E

Exponentielle Gleitkomma-Argumente.

10

~$

Dollar- und Gleitkomma-Argumente.

11

~%

Eine neue Zeile wird gedruckt.

12

~*

Das nächste Argument wird ignoriert.

13

~?

Indirektion. Das nächste Argument muss eine Zeichenfolge und das nachfolgende eine Liste sein.

Beispiel

Schreiben wir das Programm zur Berechnung der Kreisfläche neu -

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(defun AreaOfCircle()
   (terpri)
   (princ "Enter Radius: ")
   (setq radius (read))
   (setq area (* 3.1416 radius radius))
   (format t "Radius: = ~F~% Area = ~F" radius area)
)
(AreaOfCircle)

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

Enter Radius: 10.234 (STDIN Input)
Radius: = 10.234
Area = 329.03473

Wir haben diskutiert, wie Standardeingabe und -ausgabe von allgemeinem LISP behandelt werden. Alle diese Funktionen funktionieren auch zum Lesen und Schreiben in Text- und Binärdateien. Der einzige Unterschied besteht in diesem Fall darin, dass der von uns verwendete Stream keine Standardeingabe oder -ausgabe ist, sondern ein Stream, der speziell für das Schreiben oder Lesen von Dateien erstellt wurde.

In diesem Kapitel erfahren Sie, wie LISP Text- oder Binärdateien für die Datenspeicherung erstellen, öffnen, schließen kann.

Eine Datei stellt eine Folge von Bytes dar, unabhängig davon, ob es sich um eine Textdatei oder eine Binärdatei handelt. Dieses Kapitel führt Sie durch wichtige Funktionen / Makros für die Dateiverwaltung.

Dateien öffnen

Du kannst den ... benutzen openFunktion zum Erstellen einer neuen Datei oder zum Öffnen einer vorhandenen Datei. Dies ist die grundlegendste Funktion zum Öffnen einer Datei. Diewith-open-file wird normalerweise bequemer und häufiger verwendet, wie wir später in diesem Abschnitt sehen werden.

Wenn eine Datei geöffnet wird, wird ein Stream-Objekt erstellt, um sie in der LISP-Umgebung darzustellen. Alle Operationen im Stream entsprechen im Wesentlichen den Operationen in der Datei.

Syntax für die open Funktion ist -

open filename &key :direction :element-type :if-exists :if-does-not-exist :external-format

wo,

  • Das Dateinamenargument ist der Name der Datei, die geöffnet oder erstellt werden soll.

  • Die Schlüsselwortargumente geben die Art des Streams und die Fehlerbehandlungsmethoden an.

  • Das :direction Das Schlüsselwort gibt an, ob der Stream Eingabe, Ausgabe oder beides verarbeiten soll. Er nimmt die folgenden Werte an:

    • : input - für Eingabestreams (Standardwert)

    • : output - für Ausgabestreams

    • : io - für bidirektionale Streams

    • : probe - zum einfachen Überprüfen der Existenz einer Datei; Der Stream wird geöffnet und dann geschlossen.

  • Das :element-type Gibt den Typ der Transaktionseinheit für den Stream an.

  • Das :if-existsDas Argument gibt die Aktion an, die ausgeführt werden soll, wenn die Richtung: output oder: io lautet und eine Datei mit dem angegebenen Namen bereits vorhanden ist. Wenn die Richtung: input oder: probe lautet, wird dieses Argument ignoriert. Es nimmt die folgenden Werte an -

    • : error - signalisiert einen Fehler.

    • : new-version - Erstellt eine neue Datei mit demselben Namen, aber größerer Versionsnummer.

    • : rename - benennt die vorhandene Datei um.

    • : umbenennen und löschen - Die vorhandene Datei wird umbenannt und anschließend gelöscht.

    • : append - wird an die vorhandene Datei angehängt.

    • : supersede - Ersetzt die vorhandene Datei.

    • nil - Es wird keine Datei erstellt oder sogar ein Stream gibt nur nil zurück, um einen Fehler anzuzeigen.

  • Das :if-does-not-existArgument gibt die Aktion an, die ausgeführt werden soll, wenn eine Datei mit dem angegebenen Namen noch nicht vorhanden ist. Es nimmt die folgenden Werte an -

    • : error - signalisiert einen Fehler.

    • : create - Erstellt eine leere Datei mit dem angegebenen Namen und verwendet sie dann.

    • nil - Es wird keine Datei oder gar ein Stream erstellt, sondern es wird einfach nil zurückgegeben, um einen Fehler anzuzeigen.

  • Das :external-format Argument gibt ein implementierungserkanntes Schema zur Darstellung von Zeichen in Dateien an.

Sie können beispielsweise eine Datei mit dem Namen myfile.txt öffnen, die im Ordner / tmp als - gespeichert ist.

(open "/tmp/myfile.txt")

Schreiben in und Lesen aus Dateien

Das with-open-fileErmöglicht das Lesen oder Schreiben in eine Datei unter Verwendung der Stream-Variablen, die der Lese- / Schreibtransaktion zugeordnet ist. Sobald der Job erledigt ist, wird die Datei automatisch geschlossen. Es ist äußerst bequem zu bedienen.

Es hat die folgende Syntax -

with-open-file (stream filename {options}*)
   {declaration}* {form}*
  • Dateiname ist der Name der zu öffnenden Datei. Es kann sich um eine Zeichenfolge, einen Pfadnamen oder einen Stream handeln.

  • Die Optionen entsprechen den Schlüsselwortargumenten für die geöffnete Funktion.

Beispiel 1

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(with-open-file (stream "/tmp/myfile.txt" :direction :output)
   (format stream "Welcome to Tutorials Point!")
   (terpri stream)
   (format stream "This is a tutorials database")
   (terpri stream)
   (format stream "Submit your Tutorials, White Papers and Articles into our Tutorials   Directory.")
)

Bitte beachten Sie, dass alle im vorherigen Kapitel beschriebenen Eingabe-Ausgabe-Funktionen wie Terpri und Format zum Schreiben in die hier erstellte Datei funktionieren.

Wenn Sie den Code ausführen, wird nichts zurückgegeben. Unsere Daten werden jedoch in die Datei geschrieben. Das:direction :output Schlüsselwörter ermöglichen es uns, dies zu tun.

Wir können jedoch aus dieser Datei mit dem lesen read-line Funktion.

Beispiel 2

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(let ((in (open "/tmp/myfile.txt" :if-does-not-exist nil)))
   (when in
      (loop for line = (read-line in nil)
      
      while line do (format t "~a~%" line))
      (close in)
   )
)

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

Welcome to Tutorials Point!
This is a tutorials database
Submit your Tutorials, White Papers and Articles into our Tutorials Directory.

Datei schließen

Das close Funktion schließt einen Stream.

Strukturen gehören zu den benutzerdefinierten Datentypen, mit denen Sie Datenelemente verschiedener Art kombinieren können.

Strukturen werden verwendet, um einen Datensatz darzustellen. Angenommen, Sie möchten Ihre Bücher in einer Bibliothek verfolgen. Möglicherweise möchten Sie die folgenden Attribute für jedes Buch verfolgen:

  • Title
  • Author
  • Subject
  • Buch-ID

Struktur definieren

Das defstructMit dem Makro in LISP können Sie eine abstrakte Datensatzstruktur definieren. Dasdefstruct Anweisung definiert einen neuen Datentyp mit mehr als einem Mitglied für Ihr Programm.

Um das Format der zu diskutieren defstructMakro, lassen Sie uns die Definition der Buchstruktur schreiben. Wir könnten die Buchstruktur definieren als -

(defstruct book 
   title 
   author 
   subject 
   book-id 
)

bitte beachten Sie

  • Die obige Erklärung erstellt eine Buchstruktur mit vier named components. Jedes erstellte Buch wird also ein Objekt dieser Struktur sein.

  • Es definiert vier Funktionen mit den Namen Buchtitel, Buchautor, Buchsubjekt und Buchbuch-ID, die ein Argument, eine Buchstruktur, annehmen und die Felder Titel, Autor, Thema und Buch-ID des Buches zurückgeben Objekt. Diese Funktionen werden als bezeichnetaccess functions.

  • Das Symbolbuch wird zu einem Datentyp und Sie können es mit dem überprüfen typep Prädikat.

  • Es wird auch eine implizite Funktion namens geben book-p, Dies ist ein Prädikat und wird wahr sein, wenn sein Argument ein Buch ist und ansonsten falsch.

  • Eine weitere implizite Funktion namens make-book wird erstellt, das ist ein constructor, Beim Aufrufen wird eine Datenstruktur mit vier Komponenten erstellt, die für die Verwendung mit den Zugriffsfunktionen geeignet ist.

  • Das #S syntax bezieht sich auf eine Struktur, mit der Sie Instanzen eines Buches lesen oder drucken können.

  • Eine implizite Funktion namens Copy-Book eines Arguments ist ebenfalls definiert. Es nimmt ein Buchobjekt und erstellt ein anderes Buchobjekt, das eine Kopie des ersten ist. Diese Funktion heißtcopier function.

  • Sie können verwenden setf um beispielsweise die Bestandteile eines Buches zu ändern

(setf (book-book-id book3) 100)

Beispiel

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(defstruct book 
   title 
   author 
   subject 
   book-id 
)

( setq book1 (make-book :title "C Programming"
   :author "Nuha Ali" 
   :subject "C-Programming Tutorial"
   :book-id "478")
)

( setq book2 (make-book :title "Telecom Billing"
   :author "Zara Ali" 
   :subject "C-Programming Tutorial"
   :book-id "501")
) 

(write book1)
(terpri)
(write book2)
(setq book3( copy-book book1))
(setf (book-book-id book3) 100) 
(terpri)
(write book3)

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

#S(BOOK :TITLE "C Programming" :AUTHOR "Nuha Ali" :SUBJECT "C-Programming Tutorial" :BOOK-ID "478")
#S(BOOK :TITLE "Telecom Billing" :AUTHOR "Zara Ali" :SUBJECT "C-Programming Tutorial" :BOOK-ID "501")
#S(BOOK :TITLE "C Programming" :AUTHOR "Nuha Ali" :SUBJECT "C-Programming Tutorial" :BOOK-ID 100)

Im Allgemeinen handelt es sich bei einem Paket um eine Möglichkeit, einen Satz von Namen von einem anderen zu trennen. Die in einem Paket deklarierten Symbole stehen nicht in Konflikt mit denselben in einem anderen Paket deklarierten Symbolen. Auf diese Weise reduzieren Pakete die Namenskonflikte zwischen unabhängigen Codemodulen.

Der LISP-Reader führt eine Tabelle aller gefundenen Symbole. Wenn eine neue Zeichenfolge gefunden wird, wird ein neues Symbol erstellt und in der Symboltabelle gespeichert. Diese Tabelle wird als Paket bezeichnet.

Das aktuelle Paket wird von der speziellen Variablen * package * referenziert.

Es gibt zwei vordefinierte Pakete in LISP -

  • common-lisp - Es enthält Symbole für alle definierten Funktionen und Variablen.

  • common-lisp-user- Es verwendet das Common-Lisp-Paket und alle anderen Pakete mit Bearbeitungs- und Debugging-Tools. es heißt kurz cl-user

Paketfunktionen in LISP

Die folgende Tabelle enthält die am häufigsten verwendeten Funktionen zum Erstellen, Verwenden und Bearbeiten von Paketen.

Sr.Nr. Funktion und Beschreibung
1

make-package Paketname & Schlüssel: Spitznamen: verwenden

Es wird ein neues Paket mit dem angegebenen Paketnamen erstellt und zurückgegeben.

2

in-package Paketname & Schlüssel: Spitznamen: verwenden

Macht das Paket aktuell.

3

in-package Name

Dieses Makro bewirkt, dass * package * auf den Paketnamen gesetzt wird, der ein Symbol oder eine Zeichenfolge sein muss.

4

find-package Name

Es sucht nach einem Paket. Das Paket mit diesem Namen oder Spitznamen wird zurückgegeben. Wenn kein solches Paket vorhanden ist, gibt find-package nil zurück.

5

rename-package Paket neuer Name & optionale neue Spitznamen

es benennt ein Paket um.

6

list-all-packages

Diese Funktion gibt eine Liste aller Pakete zurück, die derzeit im Lisp-System vorhanden sind.

7

delete-package Paket

Es löscht ein Paket.

Erstellen eines LISP-Pakets

Das defpackageDie Funktion wird zum Erstellen eines benutzerdefinierten Pakets verwendet. Es hat die folgende Syntax -

(defpackage :package-name
   (:use :common-lisp ...)
   (:export :symbol1 :symbol2 ...)
)

Wo,

  • Paketname ist der Name des Pakets.

  • Das Schlüsselwort: use gibt die Pakete an, die dieses Paket benötigt, dh Pakete, die Funktionen definieren, die vom Code in diesem Paket verwendet werden.

  • Das Schlüsselwort: export gibt die Symbole an, die in diesem Paket extern sind.

Das make-packageDie Funktion wird auch zum Erstellen eines Pakets verwendet. Die Syntax für diese Funktion lautet -

make-package package-name &key :nicknames :use

Die Argumente und Schlüsselwörter haben dieselbe Bedeutung wie zuvor.

Verwenden eines Pakets

Sobald Sie ein Paket erstellt haben, können Sie den Code in diesem Paket verwenden, indem Sie es zum aktuellen Paket machen. Dasin-package Makro macht ein Paket in der Umgebung aktuell.

Beispiel

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(make-package :tom)
(make-package :dick)
(make-package :harry)
(in-package tom)
(defun hello () 
   (write-line "Hello! This is Tom's Tutorials Point")
)

(hello)
(in-package dick)
(defun hello () 
   (write-line "Hello! This is Dick's Tutorials Point")
)

(hello)
(in-package harry)
(defun hello () 
   (write-line "Hello! This is Harry's Tutorials Point")
)

(hello)
(in-package tom)
(hello)
(in-package dick)
(hello)
(in-package harry)
(hello)

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

Hello! This is Tom's Tutorials Point
Hello! This is Dick's Tutorials Point
Hello! This is Harry's Tutorials Point

Paket löschen

Das delete-packageMit Makro können Sie ein Paket löschen. Das folgende Beispiel zeigt dies -

Beispiel

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(make-package :tom)
(make-package :dick)
(make-package :harry)
(in-package tom)
(defun hello () 
   (write-line "Hello! This is Tom's Tutorials Point")
)

(in-package dick)
(defun hello () 
   (write-line "Hello! This is Dick's Tutorials Point")
)

(in-package harry)
(defun hello () 
   (write-line "Hello! This is Harry's Tutorials Point")
)

(in-package tom)
(hello)
(in-package dick)
(hello)
(in-package harry)
(hello)
(delete-package tom)
(in-package tom)
(hello)

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

Hello! This is Tom's Tutorials Point
Hello! This is Dick's Tutorials Point
Hello! This is Harry's Tutorials Point
*** - EVAL: variable TOM has no value

In der allgemeinen LISP-Terminologie werden Ausnahmen als Bedingungen bezeichnet.

In der Tat sind Bedingungen allgemeiner als Ausnahmen in traditionellen Programmiersprachen, weil a condition stellt jedes Auftreten, jeden Fehler oder nicht dar, das sich auf verschiedene Ebenen des Funktionsaufrufstapels auswirken kann.

Der Bedingungsbehandlungsmechanismus in LISP behandelt solche Situationen so, dass Bedingungen verwendet werden, um eine Warnung zu signalisieren (z. B. durch Drucken einer Warnung), während der Code der oberen Ebene auf dem Aufrufstapel seine Arbeit fortsetzen kann.

Das Zustandsbehandlungssystem in LISP besteht aus drei Teilen:

  • Einen Zustand signalisieren
  • Umgang mit der Bedingung
  • Starten Sie den Prozess neu

Umgang mit einer Bedingung

Nehmen wir ein Beispiel für die Behandlung einer Bedingung, die sich aus der Bedingung Division durch Null ergibt, um die Konzepte hier zu erläutern.

Sie müssen die folgenden Schritte ausführen, um eine Bedingung zu behandeln:

  • Define the Condition - "Eine Bedingung ist ein Objekt, dessen Klasse die allgemeine Natur der Bedingung angibt und dessen Instanzdaten Informationen über die Details der besonderen Umstände enthalten, die zur Signalisierung der Bedingung führen."

    Das Definitionsbedingungsmakro wird zum Definieren einer Bedingung verwendet, die die folgende Syntax hat:

    (define-condition condition-name (error)
       ((text :initarg :text :reader text))
    )

    Neue Bedingungsobjekte werden mit dem Makro MAKE-CONDITION erstellt, das die Slots der neuen Bedingung basierend auf dem initialisiert :initargs Streit.

    In unserem Beispiel definiert der folgende Code die Bedingung:

    (define-condition on-division-by-zero (error)
       ((message :initarg :message :reader message))
    )
  • Writing the Handlers- Ein Bedingungshandler ist ein Code, der zur Behandlung der darauf signalisierten Bedingung verwendet wird. Es wird im Allgemeinen in einer der übergeordneten Funktionen geschrieben, die die Fehlerfunktion aufrufen. Wenn eine Bedingung signalisiert wird, sucht der Signalisierungsmechanismus basierend auf der Klasse der Bedingung nach einem geeigneten Handler.

    Jeder Handler besteht aus -

    • Typspezifizierer, der den Typ der Bedingung angibt, mit der er umgehen kann
    • Eine Funktion, die ein einzelnes Argument akzeptiert, die Bedingung

    Wenn eine Bedingung signalisiert wird, findet der Signalisierungsmechanismus den zuletzt eingerichteten Handler, der mit dem Bedingungstyp kompatibel ist, und ruft seine Funktion auf.

    Das Makro handler-caserichtet einen Bedingungshandler ein. Die Grundform eines Handler-Falls -

    (handler-case expression error-clause*)

    Wobei jede Fehlerklausel die Form hat -

    condition-type ([var]) code)
  • Restarting Phase

    Dies ist der Code, der Ihr Programm tatsächlich von Fehlern wiederherstellt, und Bedingungshandler können dann eine Bedingung behandeln, indem sie einen geeigneten Neustart aufrufen. Der Neustartcode wird im Allgemeinen in Funktionen der mittleren oder unteren Ebene platziert, und die Bedingungshandler werden in den oberen Ebenen der Anwendung platziert.

    Das handler-bindMit dem Makro können Sie eine Neustartfunktion bereitstellen und mit den Funktionen der unteren Ebene fortfahren, ohne den Funktionsaufrufstapel abzuwickeln. Mit anderen Worten, der Steuerungsfluss befindet sich weiterhin in der Funktion der unteren Ebene.

    Die Grundform von handler-bind ist wie folgt -

    (handler-bind (binding*) form*)

    Wobei jede Bindung eine Liste der folgenden ist:

    • eine Konditionsart
    • eine Handlerfunktion eines Arguments

    Das invoke-restart Das Makro findet und ruft die zuletzt gebundene Neustartfunktion mit dem angegebenen Namen als Argument auf.

    Sie können mehrere Neustarts durchführen.

Beispiel

In diesem Beispiel demonstrieren wir die obigen Konzepte, indem wir eine Funktion namens Division-Funktion schreiben, die eine Fehlerbedingung erzeugt, wenn das Divisor-Argument Null ist. Wir haben drei anonyme Funktionen, die drei Möglichkeiten bieten, um daraus herauszukommen - indem Sie einen Wert 1 zurückgeben, einen Divisor 2 senden und neu berechnen oder 1 zurückgeben.

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(define-condition on-division-by-zero (error)
   ((message :initarg :message :reader message))
)
   
(defun handle-infinity ()
   (restart-case
      (let ((result 0))
         (setf result (division-function 10 0))
         (format t "Value: ~a~%" result)
      )
      (just-continue () nil)
   )
)
     
(defun division-function (value1 value2)
   (restart-case
      (if (/= value2 0)
         (/ value1 value2)
         (error 'on-division-by-zero :message "denominator is zero")
      )

      (return-zero () 0)
      (return-value (r) r)
      (recalc-using (d) (division-function value1 d))
   )
)

(defun high-level-code ()
   (handler-bind
      (
         (on-division-by-zero
            #'(lambda (c)
               (format t "error signaled: ~a~%" (message c))
               (invoke-restart 'return-zero)
            )
         )
         (handle-infinity)
      )
   )
)

(handler-bind
   (
      (on-division-by-zero
         #'(lambda (c)
            (format t "error signaled: ~a~%" (message c))
            (invoke-restart 'return-value 1)
         )
      )
   )
   (handle-infinity)
)

(handler-bind
   (
      (on-division-by-zero
         #'(lambda (c)
            (format t "error signaled: ~a~%" (message c))
            (invoke-restart 'recalc-using 2)
         )
      )
   )
   (handle-infinity)
)

(handler-bind
   (
      (on-division-by-zero
         #'(lambda (c)
            (format t "error signaled: ~a~%" (message c))
            (invoke-restart 'just-continue)
         )
      )
   )
   (handle-infinity)
)

(format t "Done."))

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

error signaled: denominator is zero
Value: 1
error signaled: denominator is zero
Value: 5
error signaled: denominator is zero
Done.

Neben dem oben diskutierten "Bedingungssystem" bietet Common LISP auch verschiedene Funktionen, die zum Signalisieren eines Fehlers aufgerufen werden können. Die Behandlung eines Fehlers, wenn er signalisiert wird, ist jedoch implementierungsabhängig.

Fehlersignalisierungsfunktionen in LISP

Die folgende Tabelle enthält häufig verwendete Funktionen, die Warnungen, Unterbrechungen, nicht schwerwiegende und schwerwiegende Fehler signalisieren.

Das Anwenderprogramm gibt eine Fehlermeldung (eine Zeichenfolge) an. Die Funktionen verarbeiten diese Nachricht und zeigen sie dem Benutzer möglicherweise nicht an.

Die Fehlermeldungen sollten durch Anwenden von erstellt werden format Die Funktion sollte weder am Anfang noch am Ende ein Zeilenumbruchzeichen enthalten und muss keinen Fehler anzeigen, da das LISP-System diese gemäß seinem bevorzugten Stil behandelt.

Sr.Nr. Funktion und Beschreibung
1

error Format-String & Rest Argumente

Es signalisiert einen schwerwiegenden Fehler. Es ist unmöglich, von dieser Art von Fehler fortzufahren; Daher wird der Fehler niemals zu seinem Anrufer zurückkehren.

2

cerror continue-format-string error-format-string & rest args

Es signalisiert einen Fehler und tritt in den Debugger ein. Es ermöglicht jedoch, das Programm vom Debugger aus fortzusetzen, nachdem der Fehler behoben wurde.

3

warn Format-String & Rest Argumente

Es gibt eine Fehlermeldung aus, geht aber normalerweise nicht in den Debugger

4

break& optional format-string & rest args

Es druckt die Nachricht und geht direkt in den Debugger, ohne dass programmierte Fehlerbehandlungsfunktionen abfangen können

Beispiel

In diesem Beispiel berechnet die Fakultätsfunktion die Fakultät einer Zahl. Wenn das Argument jedoch negativ ist, wird eine Fehlerbedingung ausgelöst.

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(defun factorial (x)
   (cond ((or (not (typep x 'integer)) (minusp x))
      (error "~S is a negative number." x))
      ((zerop x) 1)
      (t (* x (factorial (- x 1))))
   )
)

(write(factorial 5))
(terpri)
(write(factorial -1))

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

120
*** - -1 is a negative number.

Common LISP war einige Jahrzehnte vor dem Fortschritt der objektorientierten Programmierung. Die Objektorientierung wurde jedoch zu einem späteren Zeitpunkt einbezogen.

Klassen definieren

Das defclassMakro ermöglicht das Erstellen von benutzerdefinierten Klassen. Es legt eine Klasse als Datentyp fest. Es hat die folgende Syntax -

(defclass class-name (superclass-name*)
   (slot-description*)
   class-option*))

Die Slots sind Variablen, die Daten oder Felder speichern.

Eine Slot-Beschreibung hat die Form (Slot-Name Slot-Option *), wobei jede Option ein Schlüsselwort ist, gefolgt von einem Namen, einem Ausdruck und anderen Optionen. Die am häufigsten verwendeten Steckplatzoptionen sind -

  • :accessor Funktionsname

  • :initform Ausdruck

  • :initarg Symbol

Definieren wir beispielsweise eine Box-Klasse mit drei Slots Länge, Breite und Höhe.

(defclass Box () 
   (length 
   breadth 
   height)
)

Bereitstellung der Zugriffs- und Lese- / Schreibsteuerung für einen Steckplatz

Wenn die Slots keine Werte haben, auf die zugegriffen, gelesen oder geschrieben werden kann, sind Klassen ziemlich nutzlos.

Sie können angeben accessorsfür jeden Slot, wenn Sie eine Klasse definieren. Nehmen Sie zum Beispiel unsere Box-Klasse -

(defclass Box ()
   ((length :accessor length)
      (breadth :accessor breadth)
      (height :accessor height)
   )
)

Sie können auch separat angeben accessor Namen zum Lesen und Schreiben eines Slots.

(defclass Box ()
   ((length :reader get-length :writer set-length)
      (breadth :reader get-breadth :writer set-breadth)
      (height :reader get-height :writer set-height)
   )
)

Instanz einer Klasse erstellen

Die generische Funktion make-instance Erstellt eine neue Instanz einer Klasse und gibt sie zurück.

Es hat die folgende Syntax -

(make-instance class {initarg value}*)

Beispiel

Erstellen wir eine Box-Klasse mit drei Slots, Länge, Breite und Höhe. Wir werden drei Slot-Accessoren verwenden, um die Werte in diesen Feldern festzulegen.

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(defclass box ()
   ((length :accessor box-length)
      (breadth :accessor box-breadth)
      (height :accessor box-height)
   )
)
(setf item (make-instance 'box))
(setf (box-length item) 10)
(setf (box-breadth item) 10)
(setf (box-height item) 5)
(format t "Length of the Box is ~d~%" (box-length item))
(format t "Breadth of the Box is ~d~%" (box-breadth item))
(format t "Height of the Box is ~d~%" (box-height item))

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

Length of the Box is 10
Breadth of the Box is 10
Height of the Box is 5

Definieren einer Klassenmethode

Das defmethodMit Makro können Sie eine Methode innerhalb der Klasse definieren. Das folgende Beispiel erweitert unsere Box-Klasse um eine Methode namens volume.

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(defclass box ()
   ((length :accessor box-length)
      (breadth :accessor box-breadth)
      (height :accessor box-height)
      (volume :reader volume)
   )
)

; method calculating volume   

(defmethod volume ((object box))
   (* (box-length object) (box-breadth object)(box-height object))
)

 ;setting the values 

(setf item (make-instance 'box))
(setf (box-length item) 10)
(setf (box-breadth item) 10)
(setf (box-height item) 5)

; displaying values

(format t "Length of the Box is ~d~%" (box-length item))
(format t "Breadth of the Box is ~d~%" (box-breadth item))
(format t "Height of the Box is ~d~%" (box-height item))
(format t "Volume of the Box is ~d~%" (volume item))

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

Length of the Box is 10
Breadth of the Box is 10
Height of the Box is 5
Volume of the Box is 500

Erbe

Mit LISP können Sie ein Objekt anhand eines anderen Objekts definieren. Das nennt maninheritance.Sie können eine abgeleitete Klasse erstellen, indem Sie neue oder andere Funktionen hinzufügen. Die abgeleitete Klasse erbt die Funktionen der übergeordneten Klasse.

Das folgende Beispiel erklärt dies -

Beispiel

Erstellen Sie eine neue Quellcodedatei mit dem Namen main.lisp und geben Sie den folgenden Code ein.

(defclass box ()
   ((length :accessor box-length)
      (breadth :accessor box-breadth)
      (height :accessor box-height)
      (volume :reader volume)
   )
)

; method calculating volume   
(defmethod volume ((object box))
   (* (box-length object) (box-breadth object)(box-height object))
)
  
;wooden-box class inherits the box class  
(defclass wooden-box (box)
((price :accessor box-price)))

;setting the values 
(setf item (make-instance 'wooden-box))
(setf (box-length item) 10)
(setf (box-breadth item) 10)
(setf (box-height item) 5)
(setf (box-price item) 1000)

; displaying values
(format t "Length of the Wooden Box is ~d~%" (box-length item))
(format t "Breadth of the Wooden Box is ~d~%" (box-breadth item))
(format t "Height of the Wooden Box is ~d~%" (box-height item))
(format t "Volume of the Wooden Box is ~d~%" (volume item))
(format t "Price of the Wooden Box is ~d~%" (box-price item))

Wenn Sie den Code ausführen, wird das folgende Ergebnis zurückgegeben:

Length of the Wooden Box is 10
Breadth of the Wooden Box is 10
Height of the Wooden Box is 5
Volume of the Wooden Box is 500
Price of the Wooden Box is 1000