кажется, существует предел количеству параметров, которые может взять функция clojure.
При определении функции больше чем с 20 параметрами я получаю следующее:
#<CompilerException java.lang.RuntimeException: java.lang.RuntimeException: java.lang.Exception: Can't specify more than 20 params (NO_SOURCE_FILE:0) (NO_SOURCE_FILE:0)>
Очевидно, этого можно избежать, но я поражал этот предел, портирующий модель выполнения существующего 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)))
который является оператором DSL для вызова нейронной сети с 90 входными узлами. Может работать вокруг этого, конечно, но задавался вопросом, куда предел прибывает из.Спасибо.
Прежде всего, ограничение применяется только к обязательным позиционным аргументам ; вы всегда можете использовать регистр переменной arity ( & 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
для указанной последовательности и т. Д. - имеет больше смысла с большим количество похожих элементов, чем присвоение отдельных имен каждому из них.
(Обратите внимание, что я не претендую на то, чтобы знать природу конкретного DSL, который вы транскрибируете в Clojure, или с какими проблемами вы сталкиваетесь, просто предлагая моменты, которые могут вас заинтересовать. Если у вас действительно забавная ситуация, когда это, похоже, не применимо, возможно, вы предоставите более подробную информацию, и мы посмотрим, сможет ли кто-нибудь здесь предложить несколько полезных советов по работе с ним в 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 позиционных аргументов и аргументы и
вдобавок к этому, очевидно, возникнет странность.
Что касается обоснования, я считаю, что это связано с тем фактом, что JVM может очень эффективно отправлять вызовы методу по арности, поэтому класс clojure.lang.Fn
имеет вызов
метод перегружен для арностей до 20. Я не совсем уверен, может ли он быть выше, но я полагаю, что это не то, что люди часто требуют ... Я имею в виду, я определенно нахожу какой-либо API, указывающий на 20 позиционных аргументов функции немного подозрительны.
Ответ Михала Марчика очень хорошо говорит вам, как обойти ограничение. Если вас интересует причина этого ограничения, вы можете взглянуть на этот фрагмент источника clojure: IFn
invoke является перегруженным методом Java, реализованным интерфейсом Ifn, Рич перегружал его для поддержки до 20 аргументов. Когда вы вызываете функцию в clojure, базовая реализация вызывает объект функции, метод, который поддерживает только до 20 аргументов.
Вы можете перегрузить его, чтобы поддерживать больше, но я сомневаюсь в полезности такой вещи. Если у вас есть несколько источников ввода, их, вероятно, в любом случае можно рассматривать как массив.