绑定可以是递归的
如果函数定义用名字称呼自己,哪个函数会被调用? (比较cl-flet
vs cl-labels
行为)。
范围是词汇上的......将它们捕获在闭包中......
了解词法绑定/范围与动态绑定/范围。
cl-letf
可以用来设置动态绑定函数值,通过使用 PLACE(symbol-function 'FUNC)
对于一些功能。这类似于已弃用的flet
.
不过,可以指定任何受支持的地点——cl-letf
isn't only用于函数绑定。
你什么时候使用它们?
当您想要临时定义(或覆盖)函数时。任何给定用例所需的范围规则将决定您将使用哪个选项。
-
(cl-flet ((FUNC ARGLIST BODY...) ...) FORM...)
FUNC 仅对 FORM 中的代码可见。
-
(cl-labels ((FUNC ARGLIST BODY...) ...) FORM...)
FUNC 对 FORM 中的代码以及 FUNC 自己的 BODY 中的代码都是可见的。
-
(cl-letf (((symbol-function 'FUNC) VALUE) ...) BODY...)
在 BODY 完成评估之前,FUNC 对所有事物都是可见的。
一些(相当人为的)例子......
在第一个示例中,我们定义的临时函数是递归的 -- it 称自己为——因此我们使用cl-labels
:
(注意,这不是一个强大的阶乘实现;它仅用于演示目的。)
(defun my-factorial (number)
"Show the factorial of the argument."
(interactive "nFactorial of: ")
(cl-labels ((factorial (n) (if (eq n 1)
1
(* n (factorial (1- n))))))
(message "Factorial of %d is %d" number (factorial number))))
如果你改变cl-labels
to cl-flet
一旦内部你就会得到一个错误(factorial (1- n))
被评估,因为within我们的临时功能,没有功能factorial
是已知的。
如果你要定义一个全局的factorial
无条件返回值的函数1
:
(defun factorial (n) 1)
然后factorial
函数定义为cl-flet
等着瞧that当它调用时factorial
, and my-factorial
会计算(* n 1)
作为任何参数的值n
.
当不需要递归时,cl-flet
很好用:
(defun my-square (number)
"Show the square of the argument."
(interactive "nSquare of: ")
(cl-flet ((square (n) (* n n)))
(message "Square of %d is %d" number (square number))))
Both cl-labels
and cl-flet
提供词法作用域的函数,可见only到这些宏调用体内编写的代码;特别是not到我们可能的任何其他函数的代码calling.
如果您正在定义一个辅助函数,例如上面的示例,那么词法作用域可能就是您想要的,因为您很有可能只会在宏体内调用辅助函数。
如果你想暂时override一个现有的函数,但是,您很有可能需要您正在调用的函数来查看覆盖。在这种情况下,您需要覆盖才能具有动态范围。
在过去flet
是为临时函数提供动态作用域的方法,但是flet
现在已弃用,转而使用cl-letf
与一个“地方”(symbol-function 'FUNC)
在以下示例中,乘法函数被重写,动态作用域意味着my-square
and my-factorial
将看到并使用我们对乘法的临时定义。
(defun my-bad-square ()
"Maths gone wrong."
(interactive)
(cl-letf (((symbol-function '*) '+))
(call-interactively 'my-square)))
(defun my-bad-factorial ()
"More maths gone wrong."
(interactive)
(cl-letf (((symbol-function '*)
(lambda (x y) (- x y))))
(call-interactively 'my-factorial)))