如何在Emacs Lisp中创建临时函数

时间:2010-04-17 05:10:21

标签: emacs elisp

我正在对一堆函数进行一些繁琐的调用,但参数将在运行时确定。我写了一个简单的函数来保持我的代码DRY,但是给它一个名字是不必要的。我不在其他任何地方使用此功能。

我试图按照我在Scheme中的方式进行操作,但是我收到void-function错误:

(let ((do-work (lambda (x y z)
                  (do-x x)
                  (do-y y)
                  ;; etc
                  )))
  (cond (test-1 (do-work 'a 'b 'c))
        (test-2 (do-work 'i 'j 'k))))

我可以将其全部添加到apply(例如(apply (lambda ...) (cond ...)))中,但这不是很易读。还有更好的方法吗?

3 个答案:

答案 0 :(得分:29)

与其他lisps(但不是Scheme)一样,Emacs Lisp具有变量和函数的单独名称空间(即它是‘Lisp2’, not a ‘Lisp1;请参阅Technical Issues of Separation in Function Cells and Value Cells了解这些术语的来源和含义。)

您需要使用funcallapply来调用存储在变量中的lambda(或其他函数)。

(cond (test-1 (funcall do-work 'a 'b 'c))
      (test-2 (funcall do-work 'i 'j 'k))

如果您始终发送相同数量的参数,请使用funcall。如果您需要能够发送可变数量的参数,请使用apply

内部机制是每个符号都有multiple “cells”。 使用哪个单元格取决于where the symbol is in an evaluated form。 当符号是评估表单的第一个元素时,its “function” cell is used。 在任何其他位置,its “value” cell is used。 在您的代码中,do-work在其值单元格中具有该函数。 要将其作为一项功能使用,请使用funcallapply。 如果它在函数单元格中,您可以使用其名称作为评估表单的汽车直接调用它。 您可以使用flet or labels from the cl package完成此操作。

答案 1 :(得分:21)

(require 'cl)拉入Common Lisp包,然后使用flet代替let

(flet ((do-work (x y z)
          (do-x x)
          (do-y y)
          ;; etc
          ))
  (cond (test-1 (do-work 'a 'b 'c))
        (test-2 (do-work 'i 'j 'k))))

答案 2 :(得分:4)

你可以使用ANSI Common Lisp方式(虽然我认为有一些Emacs级别可以给你带来讨厌的外观):

(flet ((do-work (x y z)
                (do-x x)
                (do-y y)
                ;; etc
                ))
  (cond (test-1 (do-work 'a 'b 'c))
        (test-2 (do-work 'i 'j 'k))))

Dunno如果您首先要(require 'cl)(或cl-macs?)来使用flet。如果要定义递归函数,则需要使用labels IIRC。