Clojure (fn[f&;args](apply f args))的标准版本或惯用用法

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和一个非常简单的函数很容易

(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)