这其实是两个相关的问题。
a)
(flet ((myfun (x) (+ x 3)))
(myfun 3))b)
(let ((myfun (lambda (x) (+ x 3))))
(funcall myfun 3))注:
(let ((myfun (lambda (x) (+ x 3))))
(myfun 3))将抛出一个错误"myfun“未定义的运算符。
发布于 2016-01-12 22:35:59
让我们从你的第二个问题开始:
正如@sds的答案所详细讨论的那样,两者在语义上是等价的,即使大多数Common编译器更有效地编译了A(这一点可以很容易理解,因为B需要对高级函数funcall进行额外调用)。
现在,关于你的第一个问题:
一个不同之处在于,由于Common是一种Lisp-2语言(参见此问题),示例A将函数myfun的名称绑定到函数对象,而第二个则将普通的词法变量绑定到同一个功能对象。
其结果是,从实用的角度来看,从效率的角度来看,语法(如示例所示的一种更方便的调用函数对象的方法)和语义(例如,函数定义了一个命名块,以便可以编写类似于:(flet ((myfun (x) (when (< x 0) (return-from myfun 0)) (+ x 3))) (myfun -4)),在let中不可能实现)都存在差异。
但也许最重要的一点是,flet只是两个特殊操作符flet的一部分,labels用来定义本地函数(与macrolet一起定义本地宏,参见规格说明)。使用labels运算符,您可以定义递归的本地函数,这在let中是不可能的。
发布于 2016-01-12 19:41:28
let创建新的变量绑定。
flet定义本地函数。
它们的用途各不相同。
您的示例做了同样的事情,但它们可能被不同的编译(示例A更“正统”,因此更有可能更有效率)。例如,在CLISP
[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或SBCL
* (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如您所见,flet版本更有效率。
https://stackoverflow.com/questions/34752215
复制相似问题