emacs - 如何优雅地修改函数的定义

标签 emacs lisp elisp

假设在一个库中定义了一个示例函数(这道题的前提是这个库中的所有定义都不能被修改,比如“只读”):

(defun sample ()
  (foo)
  (bar)
  (baz))

我想使用这个库,但是函数sample不能满足我的要求,我想要的是:

(defun sample ()
  (foo)
  (when condition
    (bar))
  (baz))

有人告诉我使用defadvice,但我注意到defadvice 只能在调用sample 之前或之后插入代码,例如:

(before-advice ...)
(sample)
(after-advice ...)

它不能修改sample 本身的定义。那么,我怎样才能优雅地实现这一目标呢?我是否必须自己重写一个名为 my-samplesample2sample

最佳答案

sds 的答案有效,除了你可能只想在 sample 执行时通知 bar ,所以你需要通知 sample 以及为了激活并停用 bar 的建议。我的 with-temporary-advice 宏有助于实现这一点:

(defmacro with-temporary-advice (function class name &rest body)
  "Enable the specified advice, evaluate BODY, then disable the advice."
  `(unwind-protect
       (progn
         (ad-enable-advice ,function ,class ,name)
         (ad-activate ,function)
         ,@body)
     (ad-disable-advice ,function ,class ,name)
     (ad-activate ,function)))

(defadvice bar (around my-conditional-bar disable)
  ;; This advice disabled by default, and enabled dynamically.
  (when condition
    ad-do-it))

(defadvice sample (around my-sample-advice activate)
  "Make execution of `bar' conditional when running `sample'."
  (with-temporary-advice 'bar 'around 'my-conditional-bar
   ad-do-it))

请注意,如果在执行 sample 时还以其他方式调用了 bar,则该建议也将适用于这些调用,因此您应该考虑到这一点一种可能性。

或者,您可能更喜欢在需要时使用 flet 来重新定义 bar。当然,这与第一个解决方案一样需要注意。

(defadvice sample (around my-sample-advice activate)
  "Make execution of `bar' conditional when running `sample'."
  (if condition
      ad-do-it
    (flet ((bar () nil))
      ad-do-it)))

更易于阅读,但出于我不理解的原因,flet 从 Emacs 24.3 开始不再受青睐。它的文档字符串建议改用 cl-flet,但由于 cl-flet 使用词法绑定(bind),所以这实际上行不通。据我所知,听起来 flet 实际上并没有消失,但目前的建议似乎是改用建议。

另请注意,如果在 bar 中,不需要的行为取决于某些变量,那么最好使用 let 绑定(bind)在该变量上,而不是在函数上绑定(bind) flet

编辑:

当然,这些方法确实使查看正在发生的事情变得更加困难。根据具体情况,最好重新定义 sample 函数来执行您想要的操作(或者编写一个 my-sample 函数来调用它的位置,正如您所建议的那样)。

关于emacs - 如何优雅地修改函数的定义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15916124/

相关文章:

R:ess emacs,跳转到函数实现/源代码

parsing - 如何通过 org-element 优雅地解析 org-mode

git - 如何在 Emacs 缓冲区中执行 git 提交

emacs - 宏扩展 : to quote the body forms or not?

lisp - Racket中 `parameterize'和 `let'的求值顺序是怎样的?

Emacs 错误地寻找 .el 而不是 .elc

scheme - 两层 "Y-style"组合子。这很常见吗?这个有正式名称吗?

Lisp (null (QUOTE NIL)) 返回 NIL

lisp - 修改函数;保存到 lisp 中的新函数

emacs - 如何从 Emacs 中的次要模式键盘映射中删除键?