我经常发现自己想要在几个参数集合上应用函数集合.使用地图和非常简单的功能很容易.
(map
(fn invoke [f & args] (apply f args))
[- + *]
[1 2 3]
[1 2 3]
[1 2 3])
(-1 6 27)
Run Code Online (Sandbox Code Playgroud)
搜索网络会出现很多定义类似功能的库,通常称为funcall或invoke.由于Clojure对可变函数的偏爱,我不禁想到应该已经有了这个函数的默认版本.
有没有,还是有其他惯用的方法来解决这样的情况?
编辑:
另一种形式可能是
(map
(comp eval list)
[- + *]
[1 2 3]
[1 2 3]
[1 2 3])
(-1 6 27)
Run Code Online (Sandbox Code Playgroud)
由于评估,这让我感到害怕.
Mic*_*ent 10
如果你真的没有关于函数名的线索,但你知道输入和输出必须是什么,你可以尝试https://github.com/Raynes/findfn.
(find-arg [-1 6 27] map '% [- + *] [1 2 3] [1 2 3] [1 2 3])
;=> (clojure.core/trampoline)
Run Code Online (Sandbox Code Playgroud)
这告诉我们
(map trampoline [- + *] [1 2 3] [1 2 3] [1 2 3])
;=> (-1 6 27)
Run Code Online (Sandbox Code Playgroud)
实际上,你可以在蹦床中滥用蹦床作为功能.但这不是惯用语,因为它是一个Lisp-1.上面的代码评估为:
[(trampoline - 1 1 1), (trampoline + 2 2 2), (trampoline * 3 3 3)]
然后变成
[-1 6 27]
(精确地以lazyseq的形式).
正如Adrian Mouat在下面的评论中指出的那样,这可能不是解决它的首选方式.使用类似funcall的构造闻起来有点滑稽.必须有一个更清洁的解决方案.直到你找到一个,findfn
可以有所帮助;-).
编辑:这将做你想要的(如@BrandonH所提到的):
(map #(apply %1 %&) [- + *] [1 2 3] [1 2 3] [1 2 3])
Run Code Online (Sandbox Code Playgroud)
但这并不是对你的版本的改进 - 它只是使用匿名函数的简写.
我的理解是FUNCALL
在Common Lisp 中是必要的,因为它是一个Lisp-2,而Clojure是一个Lisp-1.
funcall
标准Clojure库中没有一个或等效的函数可以正常工作."apply"非常接近,但最后需要一组参数,而不是纯粹的变量.
考虑到这一点,你可以通过在末尾添加无限的nils列表(它被视为附加参数的空序列)来使用apply来"欺骗"以使其工作如下:
(map apply [- + *] [1 2 3] [1 2 3] [1 2 3] (repeat nil))
=> (-1 6 27)
Run Code Online (Sandbox Code Playgroud)
总的来说,我觉得如果你真的想经常使用这个功能,合理的方法就是定义它:
(defn funcall [f & ps]
(apply f ps))
(map funcall [- + *] [1 2 3] [1 2 3] [1 2 3])
=> (-1 6 27)
Run Code Online (Sandbox Code Playgroud)