Suche…


Syntax

  • (Funktionsname) ; Ruft das Funktionsobjekt dieses Namens ab
  • #'Name ; syntaktischer Zucker für (Funktionsname)
  • (Symbol-Funktionssymbol); gibt die an das Symbol gebundene Funktion zurück
  • (Funktionsaufrufe ...); Funktion mit Argumenten aufrufen
  • (wende die Funktion arglist an); Aufruffunktion mit Argumenten in einer Liste
  • (Anwenden der Funktion arg1 arg2 ... argn arglist); Aufruffunktion mit Argumenten, die von arg1, arg2, ..., argn und dem Rest der Liste angegeben werden

Parameter

Parameter Einzelheiten
Name ein (nicht ausgewertetes) Symbol, das eine Funktion benennt
Symbol ein Symbol
Funktion eine Funktion, die aufgerufen werden soll
args ... null oder mehr Argumente ( keine Liste von Argumenten)
Arglist eine Liste mit Argumenten, die an eine Funktion übergeben werden sollen
arg1, arg2, ..., argn Jedes ist ein einzelnes Argument, das an eine Funktion übergeben werden soll

Bemerkungen

Wenn über Lisp-ähnliche Sprachen gesprochen wird, wird häufig zwischen so genannten Lisp-1 und Lisp-2 unterschieden. In einem Lisp-1 haben Symbole nur einen Wert, und wenn sich ein Symbol auf eine Funktion bezieht, ist der Wert dieses Symbols diese Funktion. In einem Lisp-2 können Symbole getrennte zugehörige Werte und Funktionen haben. Daher ist eine spezielle Form erforderlich, um auf die in einem Symbol gespeicherte Funktion anstelle des Werts zu verweisen.

Common Lisp ist im Grunde ein Lisp-2, jedoch gibt es tatsächlich mehr als 2 Namespaces (Dinge, auf die sich Symbole beziehen können) - Symbole können sich auf Werte, Funktionen, Typen und Tags beziehen.

Definieren anonymer Funktionen

Funktionen in Common Lisp sind erstklassige Werte . Eine anonyme Funktion kann mithilfe von lambda . Hier ist zum Beispiel eine Funktion von 3 Argumenten, die wir dann mit dem Aufruf von funcall

CL-USER> (lambda (a b c) (+ a (* b c)))
#<FUNCTION (LAMBDA (A B C)) {10034F484B}>
CL-USER> (defvar *foo* (lambda (a b c) (+ a (* b c))))
*FOO*
CL-USER> (funcall *foo* 1 2 3)
7

Anonyme Funktionen können auch direkt verwendet werden. Common Lisp stellt dafür eine Syntax bereit.

((lambda (a b c) (+ a (* b c)))    ; the lambda expression as the first
                                   ; element in a form
  1 2 3)                           ; followed by the arguments

Anonyme Funktionen können auch als globale Funktionen gespeichert werden:

(let ((a-function (lambda (a b c) (+ a (* b c)))))      ; our anonymous function
  (setf (symbol-function 'some-function) a-function))   ; storing it

(some-function 1 2 3)                                   ; calling it with the name

Zitierte Lambda-Ausdrücke sind keine Funktionen

Beachten Sie, dass zitierte Lambda-Ausdrücke keine Funktionen in Common Lisp sind. Das funktioniert nicht :

(funcall '(lambda (x) x)
         42)

Um einen zitierte Lambda - Ausdruck auf eine Funktion Gebrauch zu umwandeln coerce , eval oder funcall :

CL-USER > (coerce '(lambda (x) x) 'function)
#<anonymous interpreted function 4060000A7C>

CL-USER > (eval '(lambda (x) x))
#<anonymous interpreted function 4060000B9C>

CL-USER > (compile nil '(lambda (x) x))
#<Function 17 4060000CCC>

Auf vorhandene Funktionen verweisen

Jedes Symbol in Common Lisp hat einen Slot für eine zu bindende Variable und einen separaten Slot für eine zu bindende Funktion.

Beachten Sie, dass die Benennung in diesem Beispiel nur zur Veranschaulichung dient. Globale Variablen sollten nicht foo heißen, sondern *foo* . Die letztere Notation ist eine Konvention, die deutlich macht, dass die Variable eine spezielle Variable ist, die dynamische Bindung verwendet .

CL-USER> (boundp 'foo) ;is FOO defined as a variable?
NIL
CL-USER> (defvar foo 7)
FOO
CL-USER> (boundp 'foo)
T
CL-USER> foo
7
CL-USER> (symbol-value 'foo)
7
CL-USER> (fboundp 'foo) ;is FOO defined as a function?
NIL
CL-USER> (defun foo (x y) (+ (* x x) (* y y)))
FOO
CL-USER> (fboundp 'foo)
T
CL-USER> foo
7
CL-USER> (symbol-function 'foo)
#<FUNCTION FOO>
CL-USER> (function foo)
#<FUNCTION FOO>
CL-USER> (equalp (quote #'foo) (quote (function foo)))
T
CL-USER> (eq (symbol-function 'foo) #'foo)
T
CL-USER> (foo 4 3)
25
CL-USER> (funcall foo 4 3)
;get an error: 7 is not a function
CL-USER> (funcall #'foo 4 3)
25
CL-USER> (defvar bar #'foo)
BAR
CL-USER> bar
#<FUNCTION FOO>
CL-USER> (funcall bar 4 3)
25
CL-USER> #'+
#<FUNCTION +>
CL-USER> (funcall #'+ 2 3)
5

Funktionen höherer Ordnung

Common Lisp enthält viele Funktionen höherer Ordnung, die Funktionen für Argumente übergeben und diese aufrufen. Die wichtigsten sind vielleicht die funcall und apply :

CL-USER> (list 1 2 3)
(1 2 3)
CL-USER> (funcall #'list 1 2 3)
(1 2 3)
CL-USER> (funcall #'list 1 2 3 4 5)
(1 2 3 4 5)
CL-USER> (apply #'list '(1 2 3))
(1 2 3)
CL-USER> (apply #'list 1 2 '(4 5))
(1 2 3 4 5)
CL-USER> (apply #'+ 1 (list 2 3))
6
CL-USER> (defun my-funcall (function &rest args)
           (apply function args))
MY-FUNCALL
CL-USER> (my-funcall #'list 1 2 3)
(1 2 3)

Es gibt viele andere Funktionen höherer Ordnung, die zum Beispiel eine Funktion häufig auf Elemente einer Liste anwenden.

CL-USER> (map 'list #'/ '(1 2 3 4))
(1 1/2 1/3 1/4)
CL-USER> (map 'vector #'+ '(1 2 3 4 5) #(5 4 3 2 10))
#(6 6 6 6 15)
CL-USER> (reduce #'+ '(1 2 3 4 5))
15
CL-USER> (remove-if #'evenp '(1 2 3 4 5))
(1 3 5)

Liste zusammenfassen

Mit der Reduzierfunktion können die Elemente in einer Liste zusammengefasst werden.

(reduce '+ '(1 2 3 4))
;;=> 10

Standardmäßig reduzieren führt eine linksassoziativen Reduktion, was bedeutet , dass die Summe 10 , wie berechnet wird

(+ (+ (+ 1 2) 3) 4)

Die ersten beiden Elemente werden zuerst summiert und dann wird das Ergebnis (3) zum nächsten Element (3) addiert, um 6 zu erzeugen, das wiederum zu 4 addiert wird, um das Endergebnis zu erzeugen.

Dies ist sicherer als Anwendung (zB in (anzuwenden ‚+‘ (1 2 3 4)) , da die Länge der Liste der Argumente, die übergeben werden können , um beschränkt zu gelten (siehe Call-Argumente-Limit) und reduzieren funktionieren mit Funktionen, die nur zwei Argumente benötigen.

Durch die Angabe von der Schlüsselwort - Argument-end, reduzieren wird die Liste in der anderen Richtung verarbeiten, was bedeutet , dass die Summe in der umgekehrten Reihenfolge berechnet wird. Das ist

(reduce '+ (1 2 3 4) :from-end t)
;;=> 10

rechnet

(+ 1 (+ 2 (+ 3 4)))

Implementieren von Reverse und Revappend

Common Lisp hat bereits eine Reverse - Funktion, aber wenn es nicht klappt, dann könnte es leicht reduzieren implementiert werden. Gegeben eine Liste wie

(1 2 3) === (cons 1 (cons 2 (cons 3 '())))

Die umgekehrte Liste ist

(cons 3 (cons 2 (cons 1 '()))) === (3 2 1)

Das ist vielleicht keine offensichtliche Verwendung von " verkleinern" , aber wenn wir eine "umgekehrte Nachteile" -Funktion haben, sagen wir xcons , so

(xcons 1 2) === (2 . 1)

Dann

(xcons (xcons (xcons () 1) 2) 3)

Das ist eine Reduktion.

(reduce (lambda (x y)
          (cons y x))
        '(1 2 3 4)
        :initial-value '())
;=> (4 3 2 1)

Common Lisp hat eine weitere nützliche Funktion, revappend , die eine Kombination aus reverse und append ist . Konzeptionell wird eine Liste umgedreht und an einen Schwanz angehängt:

(revappend '(3 2 1) '(4 5 6))
;;=> (1 2 3 4 5 6)

Dies kann auch mit verkleinern implementiert werden. Es ist tatsächlich dasselbe wie bei der obigen Implementierung von reverse , außer dass der Anfangswert (4 5 6) anstelle der leeren Liste sein müsste.

(reduce (lambda (x y)
          (cons y x))
        '(3 2 1)
        :initial-value '(4 5 6))
;=> (1 2 3 4 5 6)

Verschlüsse

Funktionen erinnern sich an den lexikalischen Bereich, in dem sie definiert wurden. Aus diesem Grund können wir ein Lambda in ein Let einschließen, um Abschlüsse zu definieren.

(defvar *counter* (let ((count 0))
                    (lambda () (incf count))))

(funcall *counter*) ;; => 1
(funcall *counter*) ;; = 2

Im obigen Beispiel ist die Zählervariable nur für die anonyme Funktion verfügbar. Dies wird im folgenden Beispiel deutlicher

(defvar *counter-1* (make-counter))
(defvar *counter-2* (make-counter))

(funcall *counter-1*) ;; => 1
(funcall *counter-1*) ;; => 2
(funcall *counter-2*) ;; => 1
(funcall *counter-1*) ;; => 3

Definieren von Funktionen, die Funktionen übernehmen und Funktionen zurückgeben

Ein einfaches Beispiel:

CL-USER> (defun make-apply-twice (fun)
           "return a new function that applies twice the function`fun' to its argument"
           (lambda (x)
             (funcall fun (funcall fun x))))
MAKE-APPLY-TWICE
CL-USER> (funcall (make-apply-twice #'1+) 3)
5
CL-USER> (let ((pow4 (make-apply-twice (lambda (x) (* x x)))))
           (funcall pow4 3))
81

Das klassische Beispiel für die Funktionszusammensetzung : ( fgh ) ( x ) = f ( g ( h ( x )):

CL-USER> (defun compose (&rest funs)
           "return a new function obtained by the functional compositions of the parameters"
           (if (null funs) 
               #'identity
               (let ((rest-funs (apply #'compose (rest funs))))
                 (lambda (x) (funcall (first funs) (funcall rest-funs x))))))
COMPOSE
CL-USER> (defun square (x) (* x x))
SQUARE
CL-USER> (funcall (compose #'square #'1+ #'square) 3)
100  ;; => equivalent to (square (1+ (square 3)))


Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow