从 s 表达式创建 lambda

发布于 2024-07-08 02:07:04 字数 499 浏览 13 评论 0原文

我有一个 s 表达式绑定到 Common Lisp 中的变量:

(defvar x '(+ a 2))

现在我想创建一个函数,当调用该函数时,它会在定义它的范围内计算该表达式。 我已经尝试过:

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

并且

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

但这两个都会产生一个问题:EVAL 将在顶层评估代码,因此我无法捕获表达式中包含的变量。 请注意,我不能将 LET 形式放入 EVAL 中。 有什么解决办法吗?

编辑:那么如果 EVAL 问题没有解决方案,还能怎么做呢?

编辑:有人问我到底想做什么。 我正在写一个编译器。 我想接受一个 s 表达式,其变量在定义该表达式的词法环境中关闭。 把它写成宏确实可能更好。

I have an s-expression bound to a variable in Common Lisp:

(defvar x '(+ a 2))

Now I want to create a function that when called, evaluates the expression in the scope in which it was defined. I've tried this:

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

and

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

But both of these create a problem: EVAL will evaluate the code at the top level, so I can't capture variables contained in the expression. Note that I cannot put the LET form in the EVAL. Is there any solution?

EDIT: So if there is not solution to the EVAL problem, how else can it be done?

EDIT: There was a question about what exactly I am try to do. I am writing a compiler. I want to accept an s-expression with variables closed in the lexical environment where the expression is defined. It may indeed be better to write it as a macro.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

晨曦÷微暖 2024-07-15 02:07:04

您需要创建具有必要绑定的代码。 用 LET 包裹您的代码并绑定您想要在代码中可用的每个变量:

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

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

You need to create code that has the necessary bindings. Wrap a LET around your code and bind every variable you want to make available in your code:

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

(let ((a 4))
  (eval `(let ((a ,a))
           ,*x*)))
丑疤怪 2024-07-15 02:07:04

CLISP 实现了一个扩展来评估词法环境中的形式。 由于它是一个扩展,我怀疑您无法以符合标准的方式做到这一点。

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

请参阅http://clisp.cons.org/impnotes.html#eval-environ。

CLISP implements an extension to evaluate a form in the lexical environment. From the fact that it is an extension, I suspect you can't do that in a standard-compliant way.

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

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

策马西风 2024-07-15 02:07:04

您想要解决的实际问题是什么? 最有可能的是,你试图以错误的方式解决这个问题。 词法绑定适用于词汇上出现在其范围内的事物,而不是您从外部获得的随机事物。

也许你想要一个动态关闭? 这样的事情在 Common Lisp 中并不存在,尽管它在某些 Lisp 方言中存在(比如 Pico Lisp,据我所知)。

请注意,您可以执行以下类似操作:

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

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

不过,我建议您认真考虑一下您是否真的想要这样做。

What is the actual problem that you want to solve? Most likely, you're trying to tackle it the wrong way. Lexical bindings are for things that appear lexically within their scope, not for random stuff you get from outside.

Maybe you want a dynamic closure? Such a thing doesn't exist in Common Lisp, although it does in some Lisp dialects (like Pico Lisp, as far as I understand).

Note that you can do the following, which is similar:

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

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

I advise you to think hard about whether you really want this, though.

尝蛊 2024-07-15 02:07:04

在 Common Lisp 中,你可以定义 *evalhook* ,它允许您将环境传递给 (eval ...)*evalhook* 与平台无关。

In Common Lisp you can define *evalhook* Which allows you to pass an environment to (eval ...). *evalhook* is platform independent.

看轻我的陪伴 2024-07-15 02:07:04

可以使用COMPILE将表达式编译成函数,然后在动态设置变量的环境中使用PROGV对编译后的函数进行FUNCALL。 或者,更好的是,使用 COMPILE 将表达式编译为接受变量的函数。

编译接受函数定义作为列表并将其转换为函数。 在 SBCL 的情况下,该函数被编译为机器代码并且将有效执行。

第一个选项(使用编译和 progv):

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

第二个选项:

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

It is possible to use COMPILE to compile the expression into function and then use PROGV to FUNCALL the compiled function in the environment where variables are dynamically set. Or, better, use COMPILE to compile the expression into function that accepts variables.

Compile accepts the function definition as a list and turns it into function. In case of SBCL, this function is compiled into machine code and will execute efficiently.

First option (using compile and progv):

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

Second option:

(defvar *fn* (compile nil '(lambda (a) (+ a 2))))
(funcall *fn* 4)
=>
6
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文