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

时间:2014-05-16 03:30:02

标签: lisp common-lisp 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.

如何在相同的词法范围内两次评估该表格?
如何按照我想要的次数(在相同的词汇范围内)?

与上一个问题相关 Why does SBCL eval function lose the macrolet it's running in?

2 个答案:

答案 0 :(得分:6)

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

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

(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可能效果很好。

答案 1 :(得分:1)

您无法使用eval来评估词汇范围内的表单。在eval上添加HyperSpec页面(强调添加):

  

Function EVAL

     

语法:

     

eval 表格结果*

     

参数和值:

     
      
  • 表格 - 表格。
  •   
  • 结果 - 评估表格所产生的价值。
  •   
     

说明

     

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

在环境支持中进行评估的实施

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

CLISP' ext:eval-env

  

3.1. Evaluation

     

功能(EXT:EVAL-ENV形式和可选环境)。评估表格   在给定的词汇环境中,就好像表格是其中的一部分一样   环境来自的程序。