我为什么要在Clojure中使用'apply'?
这就是Rich Hickey在其中一篇博文中所说的,但我不明白使用apply的动机。 请帮忙。
Clojure和CL最大的区别在于Clojure是一个Lisp-1,所以funcall是不需要的,apply只用于将一个函数应用到运行时定义的参数集合中。 所以,(应用f [i])可以写成(fi)。
另外,他的意思是“Clojure是Lisp-1”,funcall是不需要的? 我从来没有编程在CL。
谢谢
如果传递给函数的参数个数在编译时是不知道的(对不起,不知道Clojure的语法,请使用Scheme):
(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))) ...))
但是这很快就变成了一场噩梦。 这是应用程序进入图片的地方:
(define (call-other-n func . args) (apply other args))
它将最后一个参数列表中包含的任何数量的参数作为最后一个参数,然后调用作为第一个parameter passing的函数来应用这些值。
术语Lisp-1和Lisp-2指的是函数是否与variables在同一个命名空间中。
在Lisp-2(即2个名称空间)中,表单中的第一个项目将被作为函数名称进行计算 – 即使它实际上是具有函数值的variables的名称。 所以如果你想调用一个variables函数,你必须把variables传递给另一个函数。
在Lisp-1中,像Scheme和Clojure一样,评估函数的variables可以放在初始位置,所以你不需要使用apply
来评估它是一个函数。
apply
基本上解开一个序列并作为单独的论据应用到他们的function。
这里是一个例子:
(apply + [1 2 3 4 5])
它返回15.它基本上扩展到(+ 1 2 3 4 5)
,而不是(+ [1 2 3 4 5])
。
你可以使用apply
来将一个在多个参数上工作的函数转换为一个在一个参数序列上工作的函数。 您也可以在序列前插入参数。 例如, map
可以在几个序列上工作。 这个例子(来自ClojureDocs )使用map
来转置一个matrix。
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)
,尽pipe它不是。
关于Lisp-1和Lisp-2:1和2表示名称在给定的上下文中可以表示的事物的数量。 在Lisp-2中,可以有两个不同的东西(一个函数和一个variables),名称相同。 所以,无论哪一个可能是有效的,你需要用一些东西来装饰你的程序,以表明你的意思。 值得庆幸的是,Clojure(或Scheme …)允许一个名字表示一件事,所以不需要这样的装饰。
应用types操作的通常模式是将运行时提供的函数与一组参数(同上)组合在一起。
对clojure来说,我做得还不够充分,可以对这种特定语言的微妙之处充满信心,以确定在这种情况下使用适用性是否是绝对必要的。
应用程序对协议很有用,特别是与线程macros结合使用。 我刚刚发现了这个。 由于您不能在编译时使用&macros展开接口参数 ,因此可以使用不可预测的大小的向量。
所以我使用这个例子作为一个logging的一部分,该logging包含一些关于特定xml文件的元数据和文件本身。
(query-tree [this forms] (apply xml-> (text-id-to-tree this) forms)))
text-id-to-tree
是这个特殊logging的另一种方法,它将文件parsing成XML拉链。 在另一个文件中,我使用实现query-tree
的特定查询来扩展协议,指定要通过xml-> macro进行线程化的命令链:
(tags-with-attrs [this] (query-tree this [zf/descendants zip/node (fn [node] [(map #(% node) [:tag :attrs])])])
(注意:这个查询本身会为没有属性的标签返回很多“零”的结果,过滤和减less一个干净的唯一值列表)。
顺便说一下,zf是指clojure.contrib.zip-filter,并zip到clojure.zip。 xml->macros来自我:use
的clojure.contrib.zip-filter.xml库