Lambda SBCL&;表达式
在SBCL中,如何将lambda表达式放入结构槽[例如,Lambda SBCL&;表达式,lambda,common-lisp,sbcl,Lambda,Common Lisp,Sbcl,在SBCL中,如何将lambda表达式放入结构槽[例如,(setf(struct-slot1 struct1)'(lambda(x)(*x))],以便可以使用funcall或apply调用它?SBCL编译器抱怨:需要一个(函数符号)。有没有一种方法可以安装这样一个lambda而不必编译它或给它一个明确的名称?为什么lambda表达式不是函数?我想做如下操作:(funcall(function(struct-slot1 struct1))3)。谢谢你的见解。(注:通常我在运行之前编译lambda,
(setf(struct-slot1 struct1)'(lambda(x)(*x))
],以便可以使用funcall
或apply
调用它?SBCL编译器抱怨:需要一个(函数符号)
。有没有一种方法可以安装这样一个lambda而不必编译它或给它一个明确的名称?为什么lambda表达式不是函数?我想做如下操作:(funcall(function(struct-slot1 struct1))3)
。谢谢你的见解。(注:通常我在运行之前编译lambda,但在调试期间,我需要查看lambda的内部。)这不是特定于SBCL的,而是根据ANSI通用Lisp标准
将Lambda表达式作为列表转换为函数
以下是您的选择:
CL-USER 168 > (funcall (coerce '(lambda (x) (* x x))
'function)
4)
16
CL-USER 169 > (funcall (compile nil '(lambda (x) (* x x)))
4)
16
CL-USER 170 > (funcall (eval '(lambda (x) (* x x))) ; because LAMBDA is a macro, too
4)
16
CL-USER 171 > (funcall (eval '(function (lambda (x) (* x x))))
4)
16
请注意,lambda表达式引用的是空词法环境。因此,它无法访问周围代码中的任何词汇变量
Lambda表达式不是函数对象
为什么lambda表达式不是函数
因为它只是一个列表,而不是代码。要将lambda表达式转换为代码,必须将其转换为函数对象
其他一些(通常较旧的)Lisp允许您使用lambda表达式作为代码,但不允许使用公共Lisp。这是由标准定义的
您不能执行(funcall'(lambda(x)(+x))3)
。必须首先将lambda表达式转换为函数对象
函数是一个特殊的运算符->语法+语义
(funcall(函数(struct-slot1 struct1))3)
这已经是一个语法错误<代码>函数是一个特殊运算符,需要函数名或lambda表达式<代码>(struct-slot1 struct1)两者都不是<代码>(struct-slot1 struct1)是从结构中检索值的代码。但它不是一个函数名,而是一个符号或一个列表(setf)
。它也不是lambda表达式,类似于(lambda(…)…)
(ps:通常我在运行之前编译lambda,但在调试期间,我需要查看lambda的内部。)
试试这个:
(proclaim '(optimize (debug 3)))
在SBCL中,您还可以执行以下操作:
(sb-ext:restrict-compiler-policy 'debug 3)
。。。它为调试建立了允许的最低策略。
文件说:
另请参见WITH-COMPUTING-UNIT中的策略选项
现在,为测试定义一个简单的哈希表:
CL-USER> (defparameter *hash* (make-hash-table :test #'eq))
插入匿名函数:
CL-USER> (setf (gethash :fun *hash*) (lambda (u) (* 10 u)))
#<FUNCTION (LAMBDA (U)) {1005140E2B}>
调试器将显示:
Argument X is not a NUMBER: "oops"
[Condition of type SIMPLE-TYPE-ERROR]
Restarts:
0: [RETRY] Retry SLIME REPL evaluation request.
1: [*ABORT] Return to SLIME's top level.
2: [ABORT] abort thread (#<THREAD "repl-thread" RUNNING {10041C8033}>)
Backtrace:
0: (SB-KERNEL:TWO-ARG-* "oops" 10)
1: ((LAMBDA (U)) "oops")
2: (SB-INT:SIMPLE-EVAL-IN-LEXENV (FUNCALL (GETHASH :FUN *HASH*) "oops") #<NULL-LEXENV>)
3: (EVAL (FUNCALL (GETHASH :FUN *HASH*) "oops"))
由于调试器策略足够高,匿名函数的源代码可用,即使它是在REPL中键入的。如果您的匿名函数恰好是从源文件编译而来,则按v键将转到该文件中的相应点(对应于上面用***术语包装的表单)
如果需要,还可以在编译代码之前将其存储为数据:
(defun wrap-and-compile (code)
(let ((function (compile nil code)))
(compile nil `(lambda (&rest args)
(restart-case (apply ,function args)
(DEBUG () :report ,(format nil "~S" code)
',code))))))
(setf (gethash :wrapped *hash*)
(wrap-and-compile '(lambda (x) (* 10 x))))
(funcall (gethash :wrapped *hash*) "Boo")
调试器显示:
Argument X is not a NUMBER: "Boo"
[Condition of type SIMPLE-TYPE-ERROR]
Restarts:
0: [DEBUG] (LAMBDA (X) (* 10 X))
1: [RETRY] Retry SLIME interactive evaluation request.
2: [*ABORT] Return to SLIME's top level.
3: [ABORT] abort thread (#<THREAD "worker" RUNNING {100513A403}>)
参数X不是数字:“Boo”
[类型SIMPLE-type-ERROR的条件]
重新启动:
0:[调试](λ(X)(*10 X))
1:[重试]重试SLIME交互式评估请求。
2:[*中止]返回SLIME的顶层。
3:[中止]中止线程(#)
这有点老套,但很管用。重新启动调试将返回编译函数的原始数据。您的用例不清楚您是从某处读取输入还是从什么地方读取输入。通常您只需执行(setf(struct-slot1 struct1)(lambda(x)(*x)))
。然后你可以(funcall(struct-slot1 struct1)2)=>4
很抱歉搞混了(但是我搞混了!)我正试图用setf做一些你建议的事情,但是我需要构造lambda表达式,所以它看起来大概像(setf(struct-slot1 struct1)`(lambda(x)(*x,(+2)),它安装的是一个列表,而不是一个函数。但正如Rainer评论的那样,您可以使用强制将列表转换为函数[然后可以使用(函数lambda list(struct-slot1 struct1)]访问lambda表达式。(为了重新输入记录,我正在处理一个用户的spec文件,其中包含一些构建这些lambda表达式的宏。)我也不确定我是否理解这个用例。为什么不干脆(setf…(let((y(+2)))(lambda(x)(*xy)))
?谢谢雷纳。我忘记了强制——这就解决了问题。也谢谢你的清晰解释,根据我的观点,它比实际的公共Lisp>函数>匿名函数要好。第一个示例中的强制是必要的吗?我看到类型为(lambda(x)(*x x))
已经是函数了。@agam:这个例子是关于如何从作为数据列表的代码到有效函数->从(引号(lambda()…)
到函数。(lambda()…)
已经是函数了,因为它没有引号。有趣的是,我的匿名函数是构造的[并且在加载时可选地使用(compile nil)],因此它们本身没有源代码。您的评论让我确信,有志者事竟成!@davypough只是为了确保我尝试过这样构建的函数:(compile nil(list'lambda(list'x)(list'*'x 10)))
这仍然有效。但在任何情况下,您都可以在编译函数之前创建自己的工具,将其存储为数据。请参阅编辑。
(defun wrap-and-compile (code)
(let ((function (compile nil code)))
(compile nil `(lambda (&rest args)
(restart-case (apply ,function args)
(DEBUG () :report ,(format nil "~S" code)
',code))))))
(setf (gethash :wrapped *hash*)
(wrap-and-compile '(lambda (x) (* 10 x))))
(funcall (gethash :wrapped *hash*) "Boo")
Argument X is not a NUMBER: "Boo"
[Condition of type SIMPLE-TYPE-ERROR]
Restarts:
0: [DEBUG] (LAMBDA (X) (* 10 X))
1: [RETRY] Retry SLIME interactive evaluation request.
2: [*ABORT] Return to SLIME's top level.
3: [ABORT] abort thread (#<THREAD "worker" RUNNING {100513A403}>)