在emacs中,cl-flet和cl-letf有什么区别?

Und*_*nel 5 emacs

我知道两者都用于临时更改函数的值.除了这cl-flet是一个功能并且cl-letf是一个宏的事实,你什么时候使用它们?

phi*_*ils 11

绑定可以是递归的

如果函数定义按名称调用自身,将调用哪个函数?(比较cl-fletcl-labels行为).

范围是词汇......在封闭中捕获它们......

阅读有关词法绑定/范围与动态绑定/范围的信息.

cl-letf可以通过对某些FUNC 使用PLACE 来设置动态绑定的函数值(symbol-function 'FUNC).这与已弃用的类似flet.

但是,可以指定任何支持的PLACE - cl-letf不仅适用于功能绑定.

你什么时候使用它们?

当您想要临时定义(或覆盖)函数时.您对任何给定用例所需的范围规则将决定您将使用哪个选项.


  • (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对于绝对一切都是可见的.


一些(相当人为的)例子......

在第一个例子中,我们定义的临时函数是递归的 - 它调用自身 - 因此我们使用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))))
Run Code Online (Sandbox Code Playgroud)

如果你改变cl-labelscl-flet你会尽快内得到一个错误(factorial (1- n))的评估,因为我们暂时功能,无功能factorial而着称.

如果您要定义一个factorial无条件返回值的全局函数1:

(defun factorial (n) 1)
Run Code Online (Sandbox Code Playgroud)

然后,factorial通过定义的函数cl-flet将看到的是当它调用factorial,并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))))
Run Code Online (Sandbox Code Playgroud)

双方cl-labelscl-flet提供词法范围的功能,可见只有那些宏调用的机构内编写的代码; 并且特别是给的,我们也可以任何其他函数的代码调用.

如果你正在定义一个辅助函数,例如上面的例子中,词法作用域可能就是你想要的,因为你有可能只在宏体内调用你的助手.

但是,如果您试图临时覆盖现有函数,那么您很可能需要使用您正在调用的函数来查看覆盖.在这种情况下,您需要覆盖以具有动态范围.

过去flet是为临时函数提供动态范围的方法,但flet现在不赞成使用cl-letf'place'(symbol-function 'FUNC)

在下面的示例中,乘法函数被重写,动态范围意味着my-square并且my-factorial将查看并使用我们的乘法的临时定义.

(defun my-bad-square ()
  "Maths gone wrong."
  (interactive)
  (cl-letf (((symbol-function '*) '+))
    (call-interactively 'my-square)))
Run Code Online (Sandbox Code Playgroud)
(defun my-bad-factorial ()
  "More maths gone wrong."
  (interactive)
  (cl-letf (((symbol-function '*)
             (lambda (x y) (- x y))))
    (call-interactively 'my-factorial)))
Run Code Online (Sandbox Code Playgroud)

  • 从“ Ch ig(elisp)Generalized Variables”开始,然后阅读“ Setting Generalized Variables”节点。 (3认同)
  • 你能指出我定义 PLACE 的文档部分吗?我不清楚,从 cl-letf 的文档中,我到底可以将什么用作 PLACE。 (2认同)