Clojure (fn[f&;args](apply f args))的标准版本或惯用用法
我经常发现自己想要在几个参数集合上应用一组函数。使用map和一个非常简单的函数很容易Clojure (fn[f&;args](apply f args))的标准版本或惯用用法,clojure,Clojure,我经常发现自己想要在几个参数集合上应用一组函数。使用map和一个非常简单的函数很容易 (map (fn invoke [f & args] (apply f args)) [- + *] [1 2 3] [1 2 3] [1 2 3]) (-1 6 27) 搜索web时会发现许多库定义了类似的函数,通常称为funcall或invoke。由于Clojure对可变函数的偏好,我不禁认为应该已经有了这个函数的默认版本 (map (fn invoke [f &
(map
(fn invoke [f & args] (apply f args))
[- + *]
[1 2 3]
[1 2 3]
[1 2 3])
(-1 6 27)
搜索web时会发现许多库定义了类似的函数,通常称为funcall或invoke。由于Clojure对可变函数的偏好,我不禁认为应该已经有了这个函数的默认版本
(map
(fn invoke [f & args] (apply f args))
[- + *]
[1 2 3]
[1 2 3]
[1 2 3])
(-1 6 27)
有没有其他惯用的方法来解决这种情况
编辑:
另一种形式可能是
(map
(comp eval list)
[- + *]
[1 2 3]
[1 2 3]
[1 2 3])
(-1 6 27)
这让我很害怕,因为评估。编辑:这将满足您的需求(如@BrandonH所述): 但这并不是对您的版本的改进——它只是使用了匿名函数的缩写
我的理解是,
FUNCALL
在Common Lisp中是必需的,因为它是一个Lisp-2,而Clojure是一个Lisp-1。编辑:这将满足您的需求(如@BrandonH所述):
但这并不是对您的版本的改进——它只是使用了匿名函数的缩写
我的理解是,
FUNCALL
在Common Lisp中是必需的,因为它是一个Lisp-2,而Clojure是一个Lisp-1。我现在不能将Clojure.core函数插入到地图中,让它做你想做的事情。所以,我想说,使用你自己的版本
Matt可能是对的,没有funcall的原因是,在Lisp-1中几乎不需要它(意思是,函数和其他绑定在clojure中共享相同的名称空间)我现在不能将clojure.core函数插入到地图中,让它做你想做的事情。所以,我想说,使用你自己的版本 Matt可能是对的,因为在Lisp-1中几乎不需要funcall(这意味着函数和其他绑定在clojure中共享相同的名称空间) 问题是,如果希望允许可变数量的参数,&语法将值放在向量中,因此需要使用apply。您的解决方案在我看来很好,但正如Brandon H所指出的,您可以将其缩短为
#(应用%1%&)
正如其他回答者所指出的,它与funcall
无关,我认为在其他Lisp中使用了funcall
,以避免符号和函数之间的歧义(请注意,我在这里将函数称为(%1…
),而不是(funcall%1…
)
问题是,如果您希望允许可变数量的参数,&语法将值放入向量中,这就需要使用apply。我认为您的解决方案很好,但正如Brandon H所指出的,您可以将其缩短为#(apply%1%&)
正如其他回答者所指出的,它与
funcall
无关,我认为在其他Lisp中使用了funcall
,以避免符号和函数之间的歧义(请注意,我在这里将函数称为(%1…
,而不是(funcall%1…)
如果您确实不知道函数名,但知道输入和输出必须是什么,可以尝试
这告诉我们
(map trampoline [- + *] [1 2 3] [1 2 3] [1 2 3])
;=> (-1 6 27)
实际上,您可以在clojure中将trampoline滥用为funcall。但它很难习惯用法,因为它是Lisp-1。上面的代码计算结果为:
[(蹦床-11),(蹦床+22),(蹦床*33)]
[-1 6 27]
(准确地说,是lazyseq的形式)
正如Adrian Mouat在下面的评论中指出的,这可能不是解决问题的首选方法。使用类似funcall的构造有点滑稽。必须有一个更干净的解决方案。在找到该解决方案之前,
findfn
可能会有帮助;-).如果您确实不知道函数名,但知道输入和输出必须是什么,可以尝试
这告诉我们
(map trampoline [- + *] [1 2 3] [1 2 3] [1 2 3])
;=> (-1 6 27)
实际上,您可以在clojure中将trampoline滥用为funcall。但它很难习惯用法,因为它是Lisp-1。上面的代码计算结果为:
[(蹦床-11),(蹦床+22),(蹦床*33)]
[-1 6 27]
(准确地说,是lazyseq的形式)
正如Adrian Mouat在下面的评论中指出的那样,这可能不是解决问题的首选方法。使用类似funcall的构造有点滑稽。必须有更干净的解决方案。在找到解决方案之前,
findfn
可能会有帮助;-) 我个人认为你的第一个版本非常清晰和地道
这是一个你可能会觉得有趣的选择:
(map
apply
[- + *]
(map vector [1 2 3] [1 2 3] [1 2 3]))
=> (-1 6 27)
请注意使用(map vector…)将参数序列转置为([1 1 1][2 2][3 3])的技巧,以便它们可以在应用函数中使用。我个人认为您的第一个版本非常清晰且惯用
(map
(fn invoke [f & args] (apply f args))
[- + *]
[1 2 3]
[1 2 3]
[1 2 3])
(-1 6 27)
这是一个你可能会觉得有趣的选择:
(map
apply
[- + *]
(map vector [1 2 3] [1 2 3] [1 2 3]))
=> (-1 6 27)
请注意使用(map vector…)将参数序列转换为([1 1 1][2 2][3 3])的技巧,以便它们可以在apply函数中使用。标准Clojure库中没有一个
funcall
或等效函数可以完全这样工作。“apply”非常接近,但最后需要一组参数,而不是纯粹的变量
(map
(fn invoke [f & args] (apply f args))
[- + *]
[1 2 3]
[1 2 3]
[1 2 3])
(-1 6 27)
考虑到这一点,您可以使用apply“作弊”,通过在末尾添加无限多个nil(它们被视为附加参数的空序列),使其按如下方式工作:
总的来说,如果你真的想经常使用这个函数,我认为明智的方法就是定义它:
(defn funcall [f & ps]
(apply f ps))
(map funcall [- + *] [1 2 3] [1 2 3] [1 2 3])
=> (-1 6 27)
标准Clojure库中没有一个
funcall
或等效函数可以完全按照这种方式工作。“apply”非常接近,但最后需要一组参数,而不是纯粹的变量<
(defn my-juxt [fun-vec & val-vecs]
(for [n (range 0 (count fun-vec))]
(apply (fun-vec n) (map #(nth % n) val-vecs))))
user> (my-juxt [- + *] [1 2 3] [1 2 3] [1 2 3])
(-1 6 27)