什么时候使用“apply”和“funcall”?

时间:2010-10-05 09:30:26

标签: common-lisp

Common Lisp HyperSpec funcall条目中说

(funcall function arg1 arg2 ...) 
==  (apply function arg1 arg2 ... nil) 
==  (apply function (list arg1 arg2 ...))

由于它们在某种程度上是等效的,您何时会使用apply,何时使用funcall

3 个答案:

答案 0 :(得分:21)

如果您有一个或多个单独的参数,则应使用funcall;如果列表中包含参数,则应使用apply

(defun passargs (&rest args) (apply #'myfun args))

(defun passargs (a b) (funcall #'myfun a b))

答案 1 :(得分:6)

当参数列表仅在运行时已知时,

apply非常有用,尤其是当参数作为列表动态读取时。你仍然可以在这里使用funcall,但是你必须从列表中解包各个参数,这是不方便的。您也可以通过传递单个参数来使用apply之类的funcall。它唯一需要的是最后一个参数必须是一个列表:

> (funcall #'+ 1 2)
3
> (apply #'+ 1 2 ())
3

答案 2 :(得分:1)

嗯,我认为一个好的经验法则是:当你不能使用funcall时使用apply:后者更清晰,但也不如应用,因为它不允许你调用一个数量为参数只在运行时才知道。

当然这只是一种很好的做法,你可以系统地以丑陋的方式(系统地使用应用)这样做,但正如你可能已经注意到的那样,当一个非常相似但更干净的时候使用丑陋的方式方式可用并不常见 - lisp-y。

需要应用而不是funcall的函数示例: 您是否可以使用(map #'+ '(1 2) '(2 3))(map #'+ '(1 2) '(2 3) '(3 4))两种方式实现地图(标准函数就是这种情况)而不使用apply(或eval,这是作弊)?

编辑:正如我们已经指出的那样,写(funcall func (first list) (second list) (third list) etc.)而不是(apply func list)是愚蠢的。