Macros 未经评估而取消引用

Macros 未经评估而取消引用,macros,lisp,common-lisp,eval,Macros,Lisp,Common Lisp,Eval,我以引用的形式存储一些宏(因为事实上,它们使用复杂的词汇环境生成lambda,我更喜欢将它们存储并序列化为列表)。所以现在我在尝试: (defun play (s) (funcall (macroexpand s))) Macroexpand计算引用的lambda,因此funcall无法运行它。如何在没有eval的情况下取消引用macroexpand的结果?因为在我的情况下,这会造成无法辩解的安全漏洞 更多信息: 我得到的结果如下(在最简单的情况下): FUNCALL:#1=#'(LAMB

我以引用的形式存储一些宏(因为事实上,它们使用复杂的词汇环境生成lambda,我更喜欢将它们存储并序列化为列表)。所以现在我在尝试:

(defun play (s)
  (funcall (macroexpand s)))
Macroexpand计算引用的lambda,因此funcall无法运行它。如何在没有
eval
的情况下取消引用
macroexpand
的结果?因为在我的情况下,这会造成无法辩解的安全漏洞

更多信息:

我得到的结果如下(在最简单的情况下):

FUNCALL:#1=#'(LAMBDA(#:G6008)(SYMBOL-MACROLET NIL T))不是函数名;尝试改用符号


symbol macrolet
实际上是在lambda内部建立“棘手的词汇环境”的原因。

这有几个问题。首先,我认为这是一个问题,所以如果你表现出更多的问题,我想我们可能会找到解决办法

它与取消引号没有任何关系,因为当对带引号的表达式求值时,它不再被引用,而是变成了原始带引号表达式的数据表示形式。如果要运行数据,必须评估数据

使用
eval
无法获得当前词法范围。所以,既然你在同一篇文章中提到了
eval
,词法环境让我觉得你不会得到你想要的东西

现在制作一个函数列表没有问题,如下所示:

(list (lambda (x) (+ x x))
因为我使用了
列表
,并且lambda被计算为闭包,所以没有引用。如果它被分配给变量x,您可以使用
(funcall(car x)10)调用它;=>20

编辑 实际上,我用这个代码发出了相同的错误消息:

(defmacro test () '#'(lambda (x) x))
(macroexpand '(test))             ; ==> #'(lambda (x) x) ; t
(funcall (macroexpand '(test)) 5) ; ==>
*** - funcall: #'(lambda (x) x) is not a function name; try using a symbol
      instead
它不起作用,因为不能调用未计算的lambda。您需要调用闭包(函数),它是lambda表单求值的结果。如果您不引用它,您将在宏中进行该评估:

(defmacro test () #'(lambda (x) x))
(macroexpand '(test))             ; ==> #<function :lambda (x) x> ;
(funcall (macroexpand '(test)) 5) ; ==> 5

即使这在大多数情况下更加复杂,您也会使用闭包

这有几个问题。首先,我认为这是一个问题,所以如果你表现出更多的问题,我想我们可能会找到解决办法

它与取消引号没有任何关系,因为当对带引号的表达式求值时,它不再被引用,而是变成了原始带引号表达式的数据表示形式。如果要运行数据,必须评估数据

使用
eval
无法获得当前词法范围。所以,既然你在同一篇文章中提到了
eval
,词法环境让我觉得你不会得到你想要的东西

现在制作一个函数列表没有问题,如下所示:

(list (lambda (x) (+ x x))
因为我使用了
列表
,并且lambda被计算为闭包,所以没有引用。如果它被分配给变量x,您可以使用
(funcall(car x)10)调用它;=>20

编辑 实际上,我用这个代码发出了相同的错误消息:

(defmacro test () '#'(lambda (x) x))
(macroexpand '(test))             ; ==> #'(lambda (x) x) ; t
(funcall (macroexpand '(test)) 5) ; ==>
*** - funcall: #'(lambda (x) x) is not a function name; try using a symbol
      instead
它不起作用,因为不能调用未计算的lambda。您需要调用闭包(函数),它是lambda表单求值的结果。如果您不引用它,您将在宏中进行该评估:

(defmacro test () #'(lambda (x) x))
(macroexpand '(test))             ; ==> #<function :lambda (x) x> ;
(funcall (macroexpand '(test)) 5) ; ==> 5

即使这在大多数情况下更加复杂,您也会使用闭包

我认为在这种情况下,你会发现REPL是你的朋友。要开始,请执行以下操作:

cl-user> (defmacro foo () #'(lambda () :hi))
foo
cl-user> (foo)
#<Compiled-function (:internal foo) (Non-Global)  #x3020014F82FF>
cl-user> (funcall *)
:hi
cl-user> (macroexpand '(foo))
#<Compiled-function (:internal foo) (Non-Global)  #x3020014F82FF>
t
cl-user> (funcall *)
:hi
cl-user> 
cl user>(defmacro foo()#'(lambda():hi))
福
cl用户>(foo)
#
cl用户>(funcall*)
:嗨
cl用户>(宏扩展(foo))
#
T
cl用户>(funcall*)
:嗨
cl用户>

顺便说一下,示例中出现的lambda表单包含一个参数,而funcall没有提供参数。

我认为在这种情况下,您会发现REPL是您的朋友。要开始,请执行以下操作:

cl-user> (defmacro foo () #'(lambda () :hi))
foo
cl-user> (foo)
#<Compiled-function (:internal foo) (Non-Global)  #x3020014F82FF>
cl-user> (funcall *)
:hi
cl-user> (macroexpand '(foo))
#<Compiled-function (:internal foo) (Non-Global)  #x3020014F82FF>
t
cl-user> (funcall *)
:hi
cl-user> 
cl user>(defmacro foo()#'(lambda():hi))
福
cl用户>(foo)
#
cl用户>(funcall*)
:嗨
cl用户>(宏扩展(foo))
#
T
cl用户>(funcall*)
:嗨
cl用户>
顺便说一句,我将注意到,示例中出现的lambda表单包含一个参数,而funcall没有提供参数

Macroexpand计算引用的lambda,因此funcall无法运行它。如何 不计算宏扩展的结果?因为就我而言 会造成无法辩解的安全漏洞

我认为西尔维斯特对这个问题的评论可能就在这里;听起来你在尝试做一些可能用另一种方式做得更好的事情。也就是说,如果您有一个lambda表达式的列表,那么可以使用
强制
来获取函数对象,而不是使用
eval
。也就是说,您可以这样做:

CL-USER>(funcall'(lambda()42))
; 错误,就像你一直犯的那样
CL-USER>(funcall(强制(lambda()42)函数))
42 ; 将列表(lambda()42)转换为一个函数并调用它
这在的文档中有描述;当“输出”类型为
函数
时,对象参数会发生以下情况:

如果结果类型是function,而object是 是fbound,但它既不是全局定义的宏名称,也不是全局定义的 一个特殊的操作符,那么结果就是对象的函数值

如果结果类型为function,对象为lambda表达式, 然后结果是空词汇表中对象的闭包 环境

因此,如果有一个函数返回形式为
(lambda…
)的列表,则可以使用
强制
函数调用其结果。这包括宏扩展,尽管您可能希望使用
macroexpand-1
而不是
macroexpand
,因为
lambda
已经是一个宏,所以如果扩展太远,
(lambda()…)
将变成
(函数(lambda()…)

但是,如果您尝试使用普通的
宏扩展
,就会出现问题。考虑自己的警告:

CL-USER> (macroexpand '(my-constantly 36))
#'(LAMBDA () 36) ; not a list, but a function
T
CL-USER> (funcall (coerce (macroexpand '(my-constantly 36)) 'function))
; Error. :(
Macroexpand计算引用的lambda,因此funcall无法运行它。如何 不计算宏扩展的结果?因为就我而言 会造成无法防御的安全