Common lisp flet与let之间的差异+;芬考尔
这实际上是两个相关的问题Common lisp flet与let之间的差异+;芬考尔,common-lisp,let,Common Lisp,Let,这实际上是两个相关的问题 对于绑定函数,flet和let之间有什么区别 下面的示例A和B是否等效 (A) (B) 注意: 将抛出错误“myfun”未定义运算符。创建新的变量绑定 定义本地函数 它们有不同的用途 您的示例执行相同的操作,但它们的编译方式可能不同(示例A更“正统”,因此更有可能更有效)。例如,在: [1]>(反汇编(flet((myfun(x)(+x3)))(myfun 3))) 函数的反汇编:LAMBDA (常数0)=3 (常数1)=# 0个必需参数 0个可选参数 无静止参数 无关
[1]>(反汇编(flet((myfun(x)(+x3)))(myfun 3)))
函数的反汇编:LAMBDA
(常数0)=3
(常数1)=#
0个必需参数
0个可选参数
无静止参数
无关键字参数
4字节代码指令:
0(CONST&PUSH 0);3.
1(常数1)#
2(CALLC)
3(跳过和返回1)
无
[2] >(反汇编“(let((myfun(lambda(x)(+x3))))(funcall myfun 3)))
函数的反汇编:LAMBDA
(常数0)=#
(常数1)=3
0个必需参数
0个可选参数
无静止参数
没有关键字参数
5字节代码指令:
0(CONST&PUSH 0)#
1(加载和推送0)
2(CONST&PUSH 1);3.
3(全部1)
5(跳过和返回2)
无
或:
*(反汇编(lambda()(flet((myfun(x)(+x3)))(myfun 3)))
; 用于(LAMBDA())的反汇编
; 大小:22字节。产地:#x1003BD6D94
; 94:498B4C2460 MOV RCX,[R12+96];thread.binding-stack-pointer
; 没有arg解析入口点
; 99:48894DF8 MOV[RBP-8],RCX
; 9D:BA0000000 MOV EDX,12
; A2:488BE5 MOV RSP,RBP
; A5:F8 CLC
; A6:5D POP RBP
; A7:C3 RET
; A8:CC10断路器16;参数计数陷阱无效
无
*(分解(lambda()(let((myfun)(lambda(x)(+x3)))(funcall myfun 3)))
; 用于(LAMBDA())的反汇编
; 大小:34字节。产地:#x1003C40804
; 04:498B4C2460 MOV RCX,[R12+96];thread.binding-stack-pointer
; 没有arg解析入口点
; 09:48894DF8 MOV[RBP-8],RCX
; 0D:BA06000000 MOV EDX,6
; 12:488B0597FFFFFF MOV RAX[RIP-105]#
; 19:B902000000 MOV ECX,2
; 1E:FF7508推送QWORD PTR[RBP+8]
; 21:FF60FD JMP QWORD PTR[RAX-3]
; 24:CC10-16;参数计数陷阱无效
无
如您所见,flet的效率更高。让我们从第二个问题开始:
funcall
)
现在,关于你的第一个问题:
myfun
的名称绑定到函数对象,而第二个示例将普通词汇变量绑定到同一个函数对象
其结果是,从实用的角度来看,效率的一部分,在语法(调用函数对象的更方便的方式,如您的示例所示)和语义(例如,函数定义了一个命名块,因此可以编写如下内容:(flet((myfun)(x)(when(
,使用let
)不可能
但也许最重要的一点是,
flet
只是两个特殊操作符flet
的一部分,labels
用于定义本地函数(与macrolet
一起定义本地宏,请参阅)使用标签
操作符,您可以定义递归局部函数,这在let中是不可能的。第一个示例应该是(flet((myfun(x)(+x3)))(myfun 3))
-这不是我在A下编写的吗)?不,您的第一个版本与NB之后的代码相同。您可以在修订历史记录中对此进行检查。您必须在匿名lambda中显式创建一个块
,以启用从提前返回的,因此这不是不可能的,而是不方便的。
(flet ((myfun (x) (+ x 3)))
(myfun 3))
(let ((myfun (lambda (x) (+ x 3))))
(funcall myfun 3))
(let ((myfun (lambda (x) (+ x 3))))
(myfun 3))
[1]> (disassemble '(flet ((myfun (x) (+ x 3))) (myfun 3)))
Disassembly of function :LAMBDA
(CONST 0) = 3
(CONST 1) = #<COMPILED-FUNCTION :LAMBDA-MYFUN>
0 required arguments
0 optional arguments
No rest parameter
No keyword parameters
4 byte-code instructions:
0 (CONST&PUSH 0) ; 3
1 (CONST 1) ; #<COMPILED-FUNCTION :LAMBDA-MYFUN>
2 (CALLC)
3 (SKIP&RET 1)
NIL
[2]> (disassemble '(let ((myfun (lambda (x) (+ x 3)))) (funcall myfun 3)))
Disassembly of function :LAMBDA
(CONST 0) = #<COMPILED-FUNCTION :LAMBDA-1>
(CONST 1) = 3
0 required arguments
0 optional arguments
No rest parameter
No keyword parameters
5 byte-code instructions:
0 (CONST&PUSH 0) ; #<COMPILED-FUNCTION :LAMBDA-1>
1 (LOAD&PUSH 0)
2 (CONST&PUSH 1) ; 3
3 (FUNCALL 1)
5 (SKIP&RET 2)
NIL
* (disassemble (lambda () (flet ((myfun (x) (+ x 3))) (myfun 3))))
; disassembly for (LAMBDA ())
; Size: 22 bytes. Origin: #x1003BD6D94
; 94: 498B4C2460 MOV RCX, [R12+96] ; thread.binding-stack-pointer
; no-arg-parsing entry point
; 99: 48894DF8 MOV [RBP-8], RCX
; 9D: BA0C000000 MOV EDX, 12
; A2: 488BE5 MOV RSP, RBP
; A5: F8 CLC
; A6: 5D POP RBP
; A7: C3 RET
; A8: CC10 BREAK 16 ; Invalid argument count trap
NIL
* (disassemble (lambda () (let ((myfun (lambda (x) (+ x 3)))) (funcall myfun 3))))
; disassembly for (LAMBDA ())
; Size: 34 bytes. Origin: #x1003C40804
; 04: 498B4C2460 MOV RCX, [R12+96] ; thread.binding-stack-pointer
; no-arg-parsing entry point
; 09: 48894DF8 MOV [RBP-8], RCX
; 0D: BA06000000 MOV EDX, 6
; 12: 488B0597FFFFFF MOV RAX, [RIP-105] ; #<FUNCTION (LAMBDA
; #) ..>
; 19: B902000000 MOV ECX, 2
; 1E: FF7508 PUSH QWORD PTR [RBP+8]
; 21: FF60FD JMP QWORD PTR [RAX-3]
; 24: CC10 BREAK 16 ; Invalid argument count trap
NIL