clojure函数可以采用的参数数量似乎有限制.
定义具有20个以上参数的函数时,我收到以下内容:
#
显然这可以避免,但我正在达到这个限制,将现有DSL的执行模型移植到clojure,并且我在我的DSL中有如下构造,通过宏扩展可以非常容易地映射到函数,除了这个限制:
(defAlias nn1 ((element ?e1) (element ?e2)) number "@doc features of the elements are calculated for entry into the first neural network, the result is the score computed by the latter" (nn1-recall (nn1-feature00 ?e1 ?e2) (nn1-feature01 ?e1 ?e2) ... (nn1-feature89 ?e1 ?e2)))
这是一个用于调用具有90个输入节点的神经网络的DSL语句.当然可以解决它,但想知道限制的来源.谢谢.
首先,限制仅适用于所需的位置参数 ; 你总是可以使用变量arity case(& more-args
在函数的签名中)来处理你想要的任意数量的参数:
(defn foo [& args] (count args)) (foo 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25) ;; returns 25
事实上,乍一看,& args
很可能是您问题的正确解决方案.(例如,您将能够将一个函数映射到收集到序列中的输入节点上,loop
/ recur
通过所述序列等等. - 对于大量类似项目而言,比为每个项目分配单独的名称更有意义.
(请注意,我不会假装知道您正在转录到Clojure中的特定DSL的性质或您正在处理的问题,只是建议您可能感兴趣的点.如果您有一个非常时髦的情况,这似乎不适用,也许你可以提供更多细节,我们会看到这里是否有人可以提供一些有用的提示,以便在Clojure中处理它.)
为了完整起见,您可以将该& args
位添加到一个函数中,该函数将前19个参数作为必需的位置参数:
(defn bar [a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 a12 a13 a14 a15 a16 a17 a18 a19 & as] (+ 19 (count as))) (bar 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25) ;; returns 25
请注意,如果你指定20个位置args和&
arg顶部,那么显然会出现奇怪现象.
至于基本原理,我认为这与JVM可以非常有效地调度到arity的方法这一事实有关,因此clojure.lang.Fn
该类有invoke
超过20的arities方法重载.我不完全确定它是否可以去高于此,但我认为这不是人们经常要求的......我的意思是,我当然发现任何API指定一个函数有20多个位置参数有点怀疑.
Michal Marczyk的答案告诉你如何绕过极限.如果您对此限制的原因感兴趣,您可能想要看一眼这个clojure来源:IFn
invoke是由Ifn接口实现的java重载方法,Rich重载它以支持最多20个参数.当你在clojure中调用一个函数时,底层实现会调用函数对象上的invoke,这个方法最多只支持20个args.
你可以超载它以支持更多,但我怀疑这样的事情的效用.如果你有一堆输入源,他们可能会被视为一个数组.