我正在对一堆函数进行一些繁琐的调用,但参数将在运行时确定。我写了一个简单的函数来保持我的代码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 ...))
)中,但这不是很易读。还有更好的方法吗?
答案 0 :(得分:29)
与其他lisps(但不是Scheme)一样,Emacs Lisp具有变量和函数的单独名称空间(即它是‘Lisp2’, not a ‘Lisp1’;请参阅Technical Issues of Separation in Function Cells and Value Cells了解这些术语的来源和含义。)
您需要使用funcall
或apply
来调用存储在变量中的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
在其值单元格中具有该函数。
要将其作为一项功能使用,请使用funcall
或apply
。
如果它在函数单元格中,您可以使用其名称作为评估表单的汽车直接调用它。
您可以使用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。