Recherche…


Syntaxe

  • (nom de la fonction); récupère l'objet fonction de ce nom
  • #'prénom ; sucre syntaxique pour (nom de la fonction)
  • (symbole de fonction de symbole); renvoie la fonction liée au symbole
  • (fonction funcall args ...); fonction d'appel avec args
  • (appliquer la fonction arglist); fonction d'appel avec des arguments donnés dans une liste
  • (appliquer la fonction arg1 arg2 ... argn arglist); fonction d'appel avec des arguments donnés par arg1, arg2, ..., argn, et le reste dans la liste arglist

Paramètres

Paramètre Détails
prénom un symbole (non évalué) qui nomme une fonction
symbole un symbole
fonction une fonction qui doit être appelée
args ... zéro ou plusieurs arguments ( pas une liste d'arguments)
argliste une liste contenant des arguments à transmettre à une fonction
arg1, arg2, ..., argn chacun est un seul argument à transmettre à une fonction

Remarques

Lorsque l'on parle de langages de type Lisp, il existe une distinction commune entre ce que l'on appelle un Lisp-1 et un Lisp-2. Dans un Lisp-1, les symboles ont seulement une valeur et si un symbole fait référence à une fonction, alors la valeur de ce symbole sera cette fonction. Dans un Lisp-2, les symboles peuvent avoir des valeurs et des fonctions associées distinctes. Par conséquent, un formulaire spécial est nécessaire pour faire référence à la fonction stockée dans un symbole au lieu de la valeur.

Common Lisp est essentiellement un Lisp-2, mais il y a en fait plus de 2 espaces de noms (des éléments auxquels les symboles peuvent se référer) - les symboles peuvent se référer à des valeurs, des fonctions, des types et des tags, par exemple.

Définir des fonctions anonymes

Les fonctions en Common Lisp sont des valeurs de première classe . Une fonction anonyme peut être créée en utilisant lambda . Par exemple, voici une fonction de 3 arguments que nous appelons alors en utilisant 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

Les fonctions anonymes peuvent également être utilisées directement. Common Lisp fournit une syntaxe pour cela.

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

Les fonctions anonymes peuvent également être stockées en tant que fonctions globales:

(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

Les expressions lambda cotées ne sont pas des fonctions

Notez que les expressions lambda citées ne sont pas des fonctions dans Common Lisp. Cela ne fonctionne pas :

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

Pour convertir une expression lambda citée en une fonction, utilisez coerce , eval ou 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>

Se référant aux fonctions existantes

Tout symbole dans Common Lisp possède un emplacement pour une variable à lier et un emplacement distinct pour une fonction à lier.

Notez que la dénomination dans cet exemple est uniquement illustrative. Les variables globales ne doivent pas être nommées foo , mais *foo* . La dernière notation est une convention pour indiquer clairement que la variable est une variable spéciale utilisant la liaison dynamique .

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

Fonctions d'ordre supérieur

Common Lisp contient de nombreuses fonctions d'ordre supérieur auxquelles sont passées des fonctions pour les arguments et les appelle. Peut-être les plus fondamentaux sont funcall et 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)

Il y a beaucoup d'autres fonctions d'ordre supérieur qui, par exemple, appliquent une fonction plusieurs fois aux éléments d'une liste.

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)

Résumer une liste

La fonction de réduction peut être utilisée pour additionner les éléments d’une liste.

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

Par défaut, réduire effectue une réduction associative à gauche , ce qui signifie que la somme 10 est calculée comme suit:

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

Les deux premiers éléments sont additionnés en premier, puis ce résultat (3) est ajouté à l'élément suivant (3) pour produire 6, qui à son tour s'ajoute à 4, pour produire le résultat final.

Cela est plus sûr que l' utilisation appliquer (par exemple, dans (appliquer « + » (1 2 3 4)) parce que la longueur de la liste des arguments qui peuvent être transmis à appliquer est limitée (voir appel-arguments limite), et réduire fonctionnera avec des fonctions qui ne prennent que deux arguments.

En spécifiant l'argument mot - clé from-end , réduire traite la liste dans l'autre sens, ce qui signifie que la somme est calculée dans l'ordre inverse. C'est

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

est l'informatique

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

Implémenter l'inverse et le revappend

Common Lisp a déjà une fonction inverse , mais si ce n’était pas le cas, il pourrait être implémenté facilement en utilisant Reduce . Étant donné une liste comme

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

la liste inversée est

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

Cela peut ne pas être une utilisation évidente de réduire , mais si nous avons une fonction "renversée", disons xcons , de telle sorte que

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

alors

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

ce qui est une réduction.

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

Common Lisp a une autre fonction utile, revappend , qui est une combinaison de reverse et append . Conceptuellement, il inverse une liste et l'ajoute à une queue:

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

Cela peut également être implémenté avec réduire . En fait, c'est la même chose que l'implémentation d' inverse ci-dessus, sauf que la valeur initiale devrait être (4 5 6) au lieu de la liste vide.

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

Fermetures

Les fonctions se souviennent de la portée lexicale dans laquelle elles ont été définies. À cause de cela, nous pouvons inclure un lambda dans un let pour définir des fermetures.

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

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

Dans l'exemple ci-dessus, la variable compteur n'est accessible qu'à la fonction anonyme. Ceci est plus clairement vu dans l'exemple suivant

(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

Définition de fonctions prenant en charge des fonctions et des fonctions de retour

Un exemple simple:

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'exemple classique de composition fonctionnelle : ( 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
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow