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



如何在保留词汇上下文的同时再次评估某个内容?

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

对于需要词法范围的问题的示例,

(let ((a 1) (b 2)
      (form '(+ a b)))
  (print form)
  (print (eval form))  )
(+ a b) 
The variable A is unbound.

如何在同一词汇范围内对该形式进行两次评估?
如何根据需要(在相同的词汇范围内(进行多次eval?

与上一个问题相关为什么SBCL eval函数会丢失macrolet it';是磨合期吗?

我可能错了,但这似乎是一个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))))))

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

(let* ((a 1) 
       (b 2)
       (form (expr (+ a b))))
  (print (src form))
  (print (run form)))

注意,我从let更改为let*,因为ab都不可用于form。因此,您得到的词法环境与您运行代码来代替expr表单的情况相同

Eval既不使用一次也不使用两次。也许CLOS也能发挥同样的作用。

不能在词法范围内使用eval来评估表单。引用eval上的HyperSpec页面(增加强调(:

功能EVAL

语法:

eval 表单&Rightarrow结果*

参数和值:

  • form--一个表单
  • 结果——形式的评估值

说明:

评估当前动态环境中的表单和null词法环境

环境支持中的实施和评估

尽管标准eval不允许您指定词法环境,但某些实现可能会以实现定义的方式提供此功能。例如

CLISP的ext:eval-env

3.1评估

功能(EXT:EVAL-ENV表单和可选环境(。评估表单在给定的词汇环境中,就好像形式是环境来源的程序。

最新更新