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:
|
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
|
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