这就是Rich Hickey在其中一篇博文中所说的,但我不明白使用apply的动机。请帮忙。
Clojure和CL之间的一个很大区别是Clojure是一个Lisp-1,因此不需要funcall,apply仅用于将函数应用于运行时定义的参数集合。所以,(apply f [i])可写(f i)。
另外,“Clojure是Lisp-1”是什么意思,不需要funcall?我从未在CL中编程。
由于
答案 0 :(得分:52)
你会使用 apply ,如果传递给函数的参数数量未知在编译时(抱歉,不知道Clojure语法是什么好吧,诉诸计划):
(define (call-other-1 func arg) (func arg))
(define (call-other-2 func arg1 arg2) (func arg1 arg2))
只要在编译时知道参数的数量,就可以直接传递它们,如上例所示。但是如果在编译时不知道参数的数量,你就不能这样做(好吧,你可以尝试类似的东西):
(define (call-other-n func . args)
(case (length args)
((0) (other))
((1) (other (car args)))
((2) (other (car args) (cadr args)))
...))
但这很快就变成了一场噩梦。这就是 apply 进入图片的地方:
(define (call-other-n func . args)
(apply other args))
它接受作为最后一个参数给出的列表中包含的任意数量的参数,并将作为第一个参数传递的函数调用 apply 并使用这些值。
答案 1 :(得分:40)
术语Lisp-1和Lisp-2指的是函数是否与变量位于同一名称空间中。
在Lisp-2(即2个名称空间)中,表单中的第一个项目将被评估为函数名称 - 即使它实际上是具有函数值的变量的名称。因此,如果要调用变量函数,则必须将变量传递给另一个函数。
在Lisp-1中,与Scheme和Clojure一样,评估函数的变量可以进入初始位置,因此您不需要使用apply
来将其作为函数进行评估。
答案 2 :(得分:31)
apply
基本上打开一个序列并将该函数作为单独的参数应用于它们。
以下是一个例子:
(apply + [1 2 3 4 5])
返回15.它基本上扩展为(+ 1 2 3 4 5)
,而不是(+ [1 2 3 4 5])
。
答案 3 :(得分:6)
使用apply
将适用于多个参数的函数转换为适用于单个参数序列的函数。您还可以在序列之前插入参数。例如,map
可以处理多个序列。此示例(来自ClojureDocs)使用map
来转置矩阵。
user=> (apply map vector [[:a :b] [:c :d]])
([:a :c] [:b :d])
这里插入的一个参数是vector
。因此apply
扩展为
user=> (map vector [:a :b] [:c :d])
可爱!
PS要返回向量的向量而不是向量序列,请将整个内容包装在vec
中:
user=> (vec (apply map vector [[:a :b] [:c :d]]))
虽然我们在这里,vec
可以定义为(partial apply vector)
,但事实并非如此。
关于Lisp-1和Lisp-2:1和2表示在给定的上下文中名称可以表示的事物的数量。在Lisp-2中,您可以拥有两个具有相同名称的不同内容(函数和变量)。因此,无论哪一个都有效,你需要用一些东西来装饰你的程序,以表明你的意思。值得庆幸的是,Clojure(或Scheme ...)允许名称仅表示一件事,因此不需要这样的装饰。
答案 4 :(得分:2)
应用类型操作的通常模式是将运行时提供的函数与一组参数组合,同上。
我对clojure做得不够,能够对该特定语言的细微之处充满信心,以确定在这种情况下使用apply是否是必要的。
答案 5 :(得分:0)
Apply对协议很有用,特别是与线程宏结合使用。我刚发现了这个。由于您can't use the & macro to expand interface arguments at compile time,您可以应用不可预测大小的矢量。
因此,我将此作为一个记录之间接口的一部分,该记录包含有关特定xml文件的一些元数据和文件本身。
(query-tree [this forms]
(apply xml-> (text-id-to-tree this) forms)))
text-id-to-tree
是此特定记录的另一种方法,它将文件解析为xml拉链。在另一个文件中,我使用实现query-tree
的特定查询扩展协议,指定要通过xml->线程的命令链。宏:
(tags-with-attrs [this]
(query-tree this [zf/descendants zip/node (fn [node] [(map #(% node) [:tag :attrs])])])
(注意:这个查询本身会为没有的标签返回很多“nil”结果 属性。筛选并缩小以获得唯一值的清晰列表。)
顺便提一句,zf指的是clojure.contrib.zip-filter,并指向clojure.zip。 xml-> macro来自clojure.contrib.zip-filter.xml库,我:use