如何在lisp中进行两次eval(不使用eval)

9mj*_*mjb 1 lisp eval common-lisp

如何在保持词汇背景的同时再次评估某些内容?

* (defvar form '(+ 1 2))
form
* form
(+ 1 2)
* (eval form) ;; This loses the lexical scope (not an issue here)
3
Run Code Online (Sandbox Code Playgroud)

有关需要词法范围的问题的示例

(let ((a 1) (b 2)
      (form '(+ a b)))
  (print form)
  (print (eval form))  )
(+ a b) 
The variable A is unbound.
Run Code Online (Sandbox Code Playgroud)

如何在同一个词法范围内两次评估该表格?
我想要多少次eval(在相同的词法范围内)?

与之前的问题相关 为什么SBCL eval函数会丢失它运行的宏?

Syl*_*ter 6

我可能会弄错,但这似乎是一个XY问题.我想你的例子很简单,你的请求的原因已经消失了.你为什么需要这个?

不知道更多,我在想你可以用宏来解决这个问题:

(defun run (expr)
  (funcall expr :run))

(defun src (expr)
  (funcall expr :src))

(defmacro expr (&body rest)
  `(let ((run (lambda () ,@rest))
         (src ',@rest))
     (lambda (m)
       (case m
         (:run (funcall run))
         (otherwise src))))))
Run Code Online (Sandbox Code Playgroud)

您可以将其提供给它而不是引用您的代码expr,而是创建一个对象.这两个函数runsrc获取此对象,并在原始词法环境中运行它(因为我创建了一个thunk)或返回表达式的源.你的例子将被写成:

(let* ((a 1) 
       (b 2)
       (form (expr (+ a b))))
  (print (src form))
  (print (run form)))
Run Code Online (Sandbox Code Playgroud)

请注意,我改变了let,let*因为既不可用a也不b可用form.因此,您获得的词汇环境就像您运行代码代替expr表单一样.

Eval不使用一次也不使用两次.也许CLOS本来可以做得很好.