Question

J'ai une expression s liée à une variable dans Common Lisp:

(defvar x '(+ a 2))

Maintenant, je veux créer une fonction qui, lorsqu'elle est appelée, évalue l'expression dans la portée dans laquelle elle a été définie. J'ai essayé ceci:

(let ((a 4))
  (lambda () (eval x)))

et

(let ((a 4))
  (eval `(lambda () ,x)))

Mais les deux créent un problème: EVAL évaluera le code au niveau supérieur, donc je ne peux pas capturer les variables contenues dans l'expression. Notez que je ne peux pas mettre le formulaire LET dans EVAL. Y a-t-il une solution?

EDIT: Donc, s’il n’ya pas de solution au problème d’EVAL, comment peut-on le faire autrement?

EDIT: Il y avait une question sur ce que je veux exactement faire. J'écris un compilateur. Je veux accepter une expression s avec des variables fermées dans l'environnement lexical où l'expression est définie. Il serait peut-être préférable de l'écrire sous forme de macro.

Était-ce utile?

La solution

Vous devez créer un code comportant les liaisons nécessaires. Enroulez une LET autour de votre code et liez toutes les variables que vous voulez rendre disponibles dans votre code:

(defvar *x* '(+ a 2))

(let ((a 4))
  (eval `(let ((a ,a))
           ,*x*)))

Autres conseils

CLISP implémente une extension pour évaluer un formulaire dans l'environnement lexical. Du fait qu'il s'agisse d'une extension, je suppose que vous ne pouvez pas le faire d'une manière compatible avec les normes.

(ext:eval-env x (ext:the-environment))

Voir http://clisp.cons.org/impnotes.html#eval- environ .

Quel est le problème que vous souhaitez résoudre? Très probablement, vous essayez de l'attaquer de la mauvaise façon. Les liaisons lexicales s’appliquent aux éléments apparaissant lexicalement dans leur champ d’application, pas aux éléments aléatoires que vous obtenez de l’extérieur.

Peut-être que vous voulez une fermeture dynamique? Une telle chose n’existe pas dans Common Lisp, bien que ce soit le cas dans certains dialectes Lisp (comme le Pico Lisp, pour autant que je sache).

Notez que vous pouvez procéder comme suit:

(defvar *a*)
(defvar *x* '(+ *a* 2))  ;'

(let ((a 10))
  ;; ...
  (let ((*a* a))
    (eval *x*)))

Je vous conseille de réfléchir sérieusement à la question de savoir si vous le souhaitez vraiment.

Dans Common Lisp, vous pouvez définir * evalhook * Ce qui vous permet de passer un environnement à (eval ...) . * evalhook * est indépendant de la plate-forme.

Il est possible d’utiliser COMPILE pour compiler l’expression en fonction, puis PROGV pour FUNCALL de la fonction compilée dans l’environnement où les variables sont définies de manière dynamique. Ou mieux, utilisez COMPILE pour compiler l’expression en une fonction qui accepte les variables.

Compile accepte la définition de fonction en tant que liste et la transforme en fonction. Dans le cas de SBCL, cette fonction est compilée dans le code machine et s’exécutera efficacement.

Première option (en utilisant compile et progv):

(defvar *fn* (compile nil '(lambda () (+ a 2)))
(progv '(a) '(4) (funcall *fn*))
=>
6

Deuxième option:

(defvar *fn* (compile nil '(lambda (a) (+ a 2))))
(funcall *fn* 4)
=>
6
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top