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

Cri*_*ian 25 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))))
Run Code Online (Sandbox Code Playgroud)

我可以将它全部加入apply(例如(apply (lambda ...) (cond ...))),但这不是很可读.有没有更好的办法?

Chr*_*sen 29

像其他lisps(但不是Scheme)一样,Emacs Lisp有变量和函数的独立命名空间(即它是'Lisp 2 ',而不是'Lisp 1 ' ;参见功能单元和值单元中的分离的技术问题的原点和这些术语的含义).

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

(cond (test-1 (funcall do-work 'a 'b 'c))
      (test-2 (funcall do-work 'i 'j 'k))
Run Code Online (Sandbox Code Playgroud)

使用funcall,如果你总是会发送相同数量的参数.使用apply如果您需要能够发送可变数量的参数.

内部机制是每个符号都有多个"单元格".使用哪个单元格取决于符号在评估形式中的位置.当符号是评估表单的第一个元素时,使用其"函数"单元格.在任何其他位置,使用其"值"单元格.在您的代码中,do-work函数在其值单元格中.要将其作为您使用funcall或的功能进行访问apply.如果它在函数单元格中,您可以使用其名称作为评估表单的汽车直接调用它.你可以做到这一点用fletlabelsCL.


Sea*_*ean 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))))
Run Code Online (Sandbox Code Playgroud)