Sök…


Syntax

  • (funktionsnamn); hämtar funktionsobjektet för det namnet
  • #'namn ; syntaktiskt socker för (funktionsnamn)
  • (symbol-funktionssymbol); returnerar funktionen bunden till symbol
  • (funcall-funktion args ...); samtalsfunktion med args
  • (tillämpa funktion arglist); samtalsfunktion med argument som anges i en lista
  • (tillämp funktionen arg1 arg2 ... argn arglist); samtalsfunktion med argument som ges av arg1, arg2, ..., argn och resten i listan arglist

parametrar

Parameter detaljer
namn någon (ej utvärderad) symbol som namnger en funktion
symbol en symbol
fungera en funktion som ska kallas
args ... noll eller fler argument ( inte en lista med argument)
arglist en lista som innehåller argument som ska skickas till en funktion
arg1, arg2, ..., argn var och en är ett enda argument som ska överföras till en funktion

Anmärkningar

När man talar om Lisp-liknande språk skiljer man sig mellan vad som kallas Lisp-1 och Lisp-2. I en Lisp-1 har symboler bara ett värde och om en symbol hänvisar till en funktion kommer värdet på den symbolen att vara den funktionen. I en Lisp-2 kan symboler ha separata tillhörande värden och funktioner och därför krävs en speciell form för att hänvisa till funktionen lagrad i en symbol istället för värdet.

Common Lisp är i grunden en Lisp-2 men det finns faktiskt mer än 2 namnutrymmen (saker som symboler kan hänvisa till) - symboler kan till exempel hänvisa till värden, funktioner, typer och taggar.

Definiera anonyma funktioner

Funktioner i Common Lisp är förstklassiga värden . En anonym funktion kan skapas med lambda . Här är till exempel en funktion av funcall argument som vi sedan kallar med 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

Anonyma funktioner kan också användas direkt. Common Lisp ger en syntax för det.

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

Anonyma funktioner kan också lagras som globala funktioner:

(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

Citerade lambda-uttryck är inte funktioner

Observera att citerade lambda-uttryck inte är funktioner i Common Lisp. Detta fungerar inte :

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

För att konvertera ett citerat lambda-uttryck till en funktion använder du coerce , eval eller 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>

Med hänvisning till befintliga funktioner

Alla symboler i Common Lisp har en plats för en variabel som ska bindas och en separat lucka för en funktion som ska bindas.

Observera att namnet i det här exemplet endast är för att illustrera. Globala variabler bör inte benämnas foo , utan *foo* . Den senare notationen är en konvention för att göra det klart att variabeln är en speciell variabel med dynamisk bindning .

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

Högre ordningsfunktioner

Common Lisp innehåller många högre ordningsfunktioner som skickas funktioner för argument och kallar dem. Kanske de mest grundläggande är funcall och 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)

Det finns många andra högre ordningsfunktioner som till exempel tillämpar en funktion många gånger på element i en lista.

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)

Sammanföra en lista

Funktionen reducera kan användas för att summera elementen i en lista.

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

Som standard, minska utför en vänster-associativ reduktion, vilket innebär att summan 10 beräknas som

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

De första två elementen summeras först, och sedan läggs resultatet (3) till nästa element (3) för att producera 6, som i sin tur läggs till 4, för att producera det slutliga resultatet.

Detta är säkrare än att använda applicera (t.ex. i (applicera '+' (1 2 3 4)) eftersom längden på argumentlistan som kan passeras för att tillämpas är begränsad (se call-argument-limit ), och reducera kommer att fungera med funktioner som bara tar två argument.

Genom att ange nyckelordargumentet från slutet kommer reducering att bearbeta listan i den andra riktningen, vilket innebär att summan beräknas i omvänd ordning. Det är

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

är beräkning

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

Implementera omvänd och återlänga

Common Lisp har redan en omvänd funktion, men om den inte gjorde det, kan det implementeras enkelt med reducera . Får en lista som

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

den omvända listan är

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

Det kanske inte är en uppenbar användning av reducera , men om vi har en "omvänd nackdel" -funktion, säg xcons , så att

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

Sedan

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

vilket är en minskning.

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

Common Lisp har en annan användbar funktion, revappend , som är en kombination av omvänd och bifoga . Konceptuellt vänder den en lista och lägger den till någon svans:

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

Detta kan också implementeras med reducera . Det är faktiskt detsamma som implementeringen av omvänd ovan, förutom att initialvärdet skulle behöva (4 5 6) istället för den tomma listan.

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

nedläggningar

Funktioner kommer ihåg det lexikala omfattning de definierades i. På grund av detta kan vi omsluta en lambda i ett låt för att definiera stängningar.

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

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

I exemplet ovan är räknarvariabeln endast tillgänglig för den anonyma funktionen. Detta framgår tydligare i följande exempel

(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

Definiera funktioner som tar funktioner och returnerar funktioner

Ett enkelt exempel:

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

Det klassiska exemplet på funktionskomposition : ( 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
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow