28 votes

let et flet dans emacs lisp

Je ne sais pas si vous appelez cela la formulation canonique, mais pour lier une fonction locale, le manuel GNU me conseille d'utiliser 'flet' :

(defun adder-with-flet (x)
  (flet ( (f (x) (+ x 3)) )
    (f x))
)

Cependant, par accident, j'ai essayé (après avoir joué un peu avec Scheme) l'expression suivante, où je lie une expression lambda à une variable en utilisant 'let', et cela fonctionne également si je passe la fonction à mapcar* :

(defun adder-with-let (x)
  (let ( (f (lambda (x) (+ x 3))) )
    (car (mapcar* f (list x)) ))
)

Et les deux fonctions fonctionnent :

(adder-with-flet 3)   ==> 6
(adder-with-let 3) ==> 6

Pourquoi le second fonctionne-t-il ? Je n'ai trouvé aucune documentation dans laquelle "let" peut être utilisé pour lier des fonctions à des symboles.

30voto

user58804 Points 371

A la différence de Scheme, Emacs Lisp est une 2-Lisp ce qui signifie que chaque symbole possède deux liaisons distinctes : la liaison de valeur et la liaison de fonction. Dans un appel de fonction (a b c d) le premier symbole ( a ) est recherché à l'aide d'une fonction de liaison, le reste ( b c d ) sont recherchés à l'aide de la liaison de valeur. Forme spéciale let crée une nouvelle liaison de valeur (locale), flet crée une nouvelle fonction de liaison.

Notez que l'utilisation de la liaison par valeur ou par fonction pour la recherche dépend de l'option position en el (a b c d) et non sur l'appel de la fonction type de la valeur recherchée. En particulier, une liaison de valeur peut être résolue en fonction.

Dans votre premier exemple, vous liez en fonction f (via flet ), et ensuite faire une recherche de fonction :

(f ...)

Dans votre deuxième exemple, vous liez en valeur f à une fonction (via let ), puis utiliser une recherche de valeur :

(... f ...)

Les deux fonctionnent car vous utilisez le même type de liaison et de recherche dans chaque cas.

http://en.wikipedia.org/wiki/Common_Lisp#Comparison_with_other_Lisps

16voto

Trey Jackson Points 49816

J'ai fait une recherche rapide dans le manuel d'Emacs lisp et je n'ai trouvé aucune référence à 'flet ce qui n'est pas très surprenant puisque c'est une partie de l'histoire de l'entreprise. cl - le paquet common-lisp .

let effectuera également une liaison locale, mais elle ne se liera pas à l'objet "cellule fonctionnelle" pour ce symbole.

C'est-à-dire que ça marche :

(let ((myf (lambda (x) (list x x))))
  (eval (list myf 3)))

mais

(let ((myf (lambda (x) (list x x))))
  (myf 3))

échoue avec l'erreur : "Erreur Lisp : (void-function myf)"

flet d'un autre côté, se lie à la cellule fonctionnelle, donc ça marche :

(flet ((myf (x) (list x x)))
  (myf 3))

Remarquez que la différence est que flet vous permet d'utiliser le symbole myf directement, alors que le let ne le fait pas - vous devez utiliser une certaine indirection pour extraire la fonction de la "cellule de valeur" et l'appliquer de manière appropriée.

Dans votre exemple, le ' mapcar a fait l'équivalent de mon utilisation de 'eval .

6voto

carltonf Points 51

@d11wq il y a `funcall' dans ce but. La méthode suivante fonctionne :

(defun adder-with-let (x)
  (let ((f #'(lambda (x) (+ x 3))))
    (funcall f 3)))

(adder-with-let 3) ;=> 6

-2voto

Vous n'avez pas besoin d'utiliser flet si vous ne le souhaitez pas. Vous placez une fonction dans la cellule de fonction d'un symbole local défini à l'aide de la fonction let comme dans l'exemple suivant :

(let ((ALocalSymbol))
  (fset 'ALocalSymbol (lambda (x) (* 2 x)))
  (ALocalSymbol 4)
  )

En l'évaluant, vous obtiendrez 8. Remarquez la citation devant ALocalSymbol en (let ((ALocalSymbol))...) . Alors que setq des symboles de citation, fset ne le fait pas.

flet est une sorte de sucre syntaxique. En utilisant un simple let pour définir des symboles à valeur nulle, vous permet de choisir la "cellule" d'un symbole à définir. Vous pouvez utiliser setq pour définir la cellule de valeur du symbole ou fset pour définir la cellule de fonction.

J'espère que cela vous aidera,

Pablo

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X