首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >flet与let+funcall的区别

flet与let+funcall的区别
EN

Stack Overflow用户
提问于 2016-01-12 19:28:58
回答 2查看 719关注 0票数 4

这其实是两个相关的问题。

  1. 绑定函数的flet和let之间有什么区别?
  2. 下面的例子A和B是否等价?

a)

代码语言:javascript
复制
(flet ((myfun (x) (+ x 3)))
  (myfun 3))

b)

代码语言:javascript
复制
(let ((myfun (lambda (x) (+ x 3))))
  (funcall myfun 3))

注:

代码语言:javascript
复制
(let ((myfun (lambda (x) (+ x 3))))
  (myfun 3))

将抛出一个错误"myfun“未定义的运算符。

EN

回答 2

Stack Overflow用户

发布于 2016-01-12 22:35:59

让我们从你的第二个问题开始:

  1. 下面的例子A和B是否等价?

正如@sds的答案所详细讨论的那样,两者在语义上是等价的,即使大多数Common编译器更有效地编译了A(这一点可以很容易理解,因为B需要对高级函数funcall进行额外调用)。

现在,关于你的第一个问题:

  1. 绑定函数的flet和let之间有什么区别?

一个不同之处在于,由于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中是不可能的。

票数 4
EN

Stack Overflow用户

发布于 2016-01-12 19:41:28

let创建新的变量绑定。

flet定义本地函数。

它们的用途各不相同。

您的示例做了同样的事情,但它们可能被不同的编译(示例A更“正统”,因此更有可能更有效率)。例如,在CLISP

代码语言:javascript
复制
[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

代码语言:javascript
复制
*  (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版本更有效率。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34752215

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档