这就是Rich Hickey在其中一篇博文中所说的,但我不明白使用apply的动机.请帮忙.
Clojure和CL之间的一个很大区别是Clojure是一个Lisp-1,因此不需要funcall,apply仅用于将函数应用于运行时定义的参数集合.因此,(apply f [i])可以写成(fi).
另外,"Clojure是Lisp-1"是什么意思,不需要funcall?我从未在CL编程.
谢谢
Dir*_*irk 53
如果传递给函数的参数数量在编译时是未知的,那么你会使用apply(对不起,不知道Clojure语法那么好,诉诸于Scheme):
(define (call-other-1 func arg) (func arg))
(define (call-other-2 func arg1 arg2) (func arg1 arg2))
Run Code Online (Sandbox Code Playgroud)
只要在编译时知道参数的数量,就可以直接传递它们,如上例所示.但是如果在编译时不知道参数的数量,你就不能这样做(好吧,你可以尝试类似的东西):
(define (call-other-n func . args)
(case (length args)
((0) (other))
((1) (other (car args)))
((2) (other (car args) (cadr args)))
...))
Run Code Online (Sandbox Code Playgroud)
但这很快就变成了一场噩梦.这是适用的地方进入图片:
(define (call-other-n func . args)
(apply other args))
Run Code Online (Sandbox Code Playgroud)
它接受作为最后一个参数给出的列表中包含的任意数量的参数,并调用作为第一个参数传递的函数来应用这些值.
Chu*_*uck 40
术语Lisp-1和Lisp-2指的是函数是否与变量位于同一名称空间中.
在Lisp-2(即2个名称空间)中,表单中的第一个项目将被评估为函数名称 - 即使它实际上是具有函数值的变量的名称.因此,如果要调用变量函数,则必须将变量传递给另一个函数.
在Lisp-1中,与Scheme和Clojure一样,求值函数的变量可以放在初始位置,因此您无需使用apply它来将其作为函数进行求值.
Ray*_*yne 31
apply 基本上解开一个序列并将函数作为单独的参数应用于它们.
这是一个例子:
(apply + [1 2 3 4 5])
Run Code Online (Sandbox Code Playgroud)
返回15.它基本上扩展为(+ 1 2 3 4 5),而不是(+ [1 2 3 4 5]).
您可以使用apply将处理多个参数的函数转换为适用于单个参数序列的函数.您还可以在序列之前插入参数.例如,map可以处理多个序列.此示例(来自ClojureDocs)用于map转置矩阵.
user=> (apply map vector [[:a :b] [:c :d]])
([:a :c] [:b :d])
Run Code Online (Sandbox Code Playgroud)
这里插入的一个参数是vector.所以apply扩展到了
user=> (map vector [:a :b] [:c :d])
Run Code Online (Sandbox Code Playgroud)
可爱!
PS要返回向量的向量而不是向量序列,请将整个内容包装在vec:
user=> (vec (apply map vector [[:a :b] [:c :d]]))
Run Code Online (Sandbox Code Playgroud)
虽然我们在这里,vec但可以定义为(partial apply vector),尽管不是.
关于Lisp-1和Lisp-2:1和2表示名称在给定上下文中可以表示的事物的数量.在Lisp-2中,您可以拥有两个具有相同名称的不同内容(函数和变量).因此,无论哪一个都有效,你需要用一些东西来装饰你的程序,以表明你的意思.值得庆幸的是,Clojure(或Scheme ...)允许名称仅表示一件事,因此不需要这样的装饰.
| 归档时间: |
|
| 查看次数: |
15058 次 |
| 最近记录: |