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

时间:2016-09-17 18:55:20

标签: emacs

据我所知,两者都用于临时更改函数的值。除了cl-flet是一个函数而cl-letf是一个宏,你什么时候使用它们?

1 个答案:

答案 0 :(得分:9)

  

绑定可以是递归的

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

  

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

阅读词汇绑定/范围与动态绑定/范围。

cl-letf可用于设置动态绑定函数值,对某些FUNC使用(symbol-function 'FUNC)的PLACE。这类似于已弃用的flet

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

  

你什么时候使用它们?

当您想要临时定义(或覆盖)某个功能时。对于任何给定的用例,您需要的范围规则将决定您将使用哪个选项。

  • (cl-flet ((FUNC ARGLIST BODY...) ...) FORM...)

    FUNC仅对FORM中的代码可见。

  • (cl-labels ((FUNC ARGLIST BODY...) ...) FORM...)

    对于FORM中的代码以及FUNC自己的身体中的代码都可以看到FUNC。

  • (cl-letf (((symbol-function 'FUNC) VALUE) ...) BODY...)

    在BODY完成评估之前,绝对可以看到FUNC。

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

在第一个例子中,我们定义的临时函数是递归 - 它调用自身 - 因此我们使用cl-labels

(n.b。这不是一个强有力的因子实现;它仅用于演示目的。)

(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更改为cl-flet,则会在评估内部(factorial (1- n))时出现错误,因为我们的临时函数中,没有函数factorial已知。

如果您要定义全局factorial函数,该函数无条件地返回值1

(defun factorial (n) 1)

然后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))))

cl-labelscl-flet都提供了词法范围的函数,只显示 到在这些宏调用的正文中编写的代码;特别是到我们可能调用的任何其他函数的代码。

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

但是,如果您尝试暂时覆盖现有功能,那么您很可能需要使用您正在呼叫的功能来查看覆盖。在这种情况下,您需要覆盖以具有动态范围。

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

在以下示例中,将覆盖乘法函数,动态范围意味着my-squaremy-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)))