Common lisp 你什么时候用“;套用;什么时候;funcall";?

Common lisp 你什么时候用“;套用;什么时候;funcall";?,common-lisp,Common Lisp,公共Lisp HyperSpec在funcall条目中指出 (funcall function arg1 arg2 ...) == (apply function arg1 arg2 ... nil) == (apply function (list arg1 arg2 ...)) 由于它们在某种程度上是等价的,您什么时候会使用apply,什么时候会使用funcall?如果您有一个或多个单独的参数,那么应该使用funcall,如果您的参数在列表中,那么应该使用apply (defun

公共Lisp HyperSpec在
funcall
条目中指出

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

由于它们在某种程度上是等价的,您什么时候会使用
apply
,什么时候会使用
funcall

如果您有一个或多个单独的参数,那么应该使用
funcall
,如果您的参数在列表中,那么应该使用
apply

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


我认为一个很好的经验法则是:在不能使用funcall时使用apply:后者比apply更清晰,但也不太一般,因为它不允许调用只有在运行时才知道参数数量的函数

当然,这只是一种很好的实践,您可以系统地使用丑陋的方式(系统地使用apply)来实现这一点,但是您可能已经注意到,当一种非常相似但更干净的方式可用时,使用丑陋的方式并不是很常见的-lisp-y

需要应用而不是funcall的函数示例: 您能否以这样的方式实现map,即
(map#'+'(12)'(23))
(map#'+'(12)'(23)'(34))
两种方法都可以工作(这是标准函数的情况),而不使用apply(或eval,这是欺骗)


编辑:正如已经指出的,如果只在运行时才知道参数列表,则编写:
(funcall func(第一个列表)(第二个列表)(第三个列表)等)
而不是
(应用func列表)
应用
非常有用,尤其是当参数作为列表动态读取时。您仍然可以在此处使用
funcall
,但必须从列表中解压缩各个参数,这很不方便。您还可以通过传入各个参数来使用
apply
类似
funcall
。它唯一需要的是最后一个参数必须是一个列表:

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