Ricerca…


Sintassi

  • (nome della funzione); recupera l'oggetto funzione di quel nome
  • #'nome ; zucchero sintattico per (nome della funzione)
  • (simbolo funzione-simbolo); restituisce la funzione associata al simbolo
  • (funzione funcall args ...); chiama la funzione con args
  • (applicare la funzione arglist); chiamare la funzione con argomenti forniti in una lista
  • (applicare la funzione arg1 arg2 ... argn arglist); funzione di chiamata con argomenti forniti da arg1, arg2, ..., argn e il resto nell'elenco lista

Parametri

Parametro Dettagli
nome un simbolo (non valutato) che indica una funzione
simbolo un simbolo
funzione una funzione che deve essere chiamata
args ... zero o più argomenti ( non un elenco di argomenti)
arglist un elenco contenente argomenti da passare a una funzione
arg1, arg2, ..., argn ognuno è un singolo argomento da passare a una funzione

Osservazioni

Quando si parla di lingue simili al Lisp, esiste una distinzione comune tra ciò che è noto come Lisp-1 e Lisp-2. In un Lisp-1, i simboli hanno solo un valore e se un simbolo fa riferimento a una funzione, il valore di quel simbolo sarà quella funzione. In un Lisp-2, i simboli possono avere valori e funzioni associati separati e quindi è necessario un modulo speciale per fare riferimento alla funzione memorizzata in un simbolo anziché al valore.

Common Lisp è fondamentalmente un Lisp-2, tuttavia ci sono in realtà più di 2 namespace (cose a cui i simboli possono fare riferimento) - i simboli possono riferirsi a valori, funzioni, tipi e tag, per esempio.

Definire funzioni anonime

Le funzioni in Common Lisp sono valori di prima classe . Una funzione anonima può essere creata usando lambda . Per esempio, qui c'è una funzione di 3 argomenti che chiamiamo usando 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

Le funzioni anonime possono anche essere utilizzate direttamente. Common Lisp fornisce una sintassi per questo.

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

Le funzioni anonime possono anche essere memorizzate come funzioni globali:

(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

Le espressioni lambda citate non sono funzioni

Si noti che le espressioni lambda citate non sono funzioni in Common Lisp. Questo non funziona:

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

Per convertire un'espressione lambda quotato ad un uso funzione di coerce , eval o 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>

Riferendosi a funzioni esistenti

Qualsiasi simbolo in Common Lisp ha uno slot per il vincolo di una variabile e uno slot separato per una funzione da associare.

Si noti che la denominazione in questo esempio è solo per illustrazione. Le variabili globali non dovrebbero essere denominate foo , ma *foo* . Quest'ultima notazione è una convenzione per chiarire che la variabile è una variabile speciale che utilizza l' associazione dinamica .

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

Funzioni di ordine superiore

Common Lisp contiene molte funzioni di ordine superiore che sono passate funzioni per argomenti e chiamarle. Forse i più fondamentali sono funcall e si 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)

Esistono molte altre funzioni di ordine superiore che, ad esempio, applicano una funzione molte volte agli elementi di una 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)

Sommando una lista

La funzione di riduzione può essere utilizzata per sommare gli elementi in una lista.

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

Per impostazione predefinita, ridurre esegue una riduzione associativa a sinistra , il che significa che la somma 10 viene calcolata come

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

I primi due elementi vengono sommati per primi, e quindi quel risultato (3) viene aggiunto all'elemento successivo (3) per produrre 6, che a sua volta viene aggiunto a 4, per produrre il risultato finale.

Questo è più sicuro dell'uso apply (ad esempio, in (applica '+' (1 2 3 4)) perché la lunghezza dell'elenco di argomenti che può essere passato ad applicare è limitata (vedi call-arguments-limit ), e ridurrà funzionerà con funzioni che richiedono solo due argomenti.

Specificando l'argomento parola chiave from-end , ridurre elaborerà l'elenco nell'altra direzione, il che significa che la somma viene calcolata nell'ordine inverso. Questo è

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

è informatica

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

Implementare reverse e revappend

Common Lisp ha già una funzione inversa , ma se non lo fosse, allora potrebbe essere implementato facilmente usando riduci . Dato un elenco come

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

la lista invertita è

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

Questo potrebbe non essere un uso ovvio di ridurre , ma se abbiamo una funzione "contro-invertita", diciamo xcons , così

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

Poi

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

che è una riduzione.

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

Common Lisp ha un'altra funzione utile, revappend , che è una combinazione di reverse e append . Concettualmente, inverte una lista e la aggiunge a qualche coda:

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

Questo può anche essere implementato con riduzione . In realtà, è lo stesso dell'implementazione del reverse sopra, eccetto che il valore iniziale dovrebbe essere (4 5 6) invece della lista vuota.

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

chiusure

Le funzioni ricordano l'ambito lessicale in cui sono definite. Per questo motivo, possiamo racchiudere un lambda in una finestra per definire chiusure.

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

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

Nell'esempio sopra, la variabile contatore è accessibile solo alla funzione anonima. Questo è più chiaramente visto nel seguente esempio

(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

Definire funzioni che assumono funzioni e restituiscono funzioni

Un semplice esempio:

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

L'esempio classico della composizione della funzione : ( 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
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow