Почему там предел макс. 20 параметров к функции clojure

кажется, существует предел количеству параметров, которые может взять функция 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 входными узлами. Может работать вокруг этого, конечно, но задавался вопросом, куда предел прибывает из.Спасибо.

11
задан Nathan Shively-Sanders 29 April 2010 в 13:28
поделиться

2 ответа

Прежде всего, ограничение применяется только к обязательным позиционным аргументам ; вы всегда можете использовать регистр переменной 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 позиционных аргументов функции немного подозрительны.

17
ответ дан 3 December 2019 в 03:17
поделиться

Ответ Михала Марчика очень хорошо говорит вам, как обойти ограничение. Если вас интересует причина этого ограничения, вы можете взглянуть на этот фрагмент источника clojure: IFn

invoke является перегруженным методом Java, реализованным интерфейсом Ifn, Рич перегружал его для поддержки до 20 аргументов. Когда вы вызываете функцию в clojure, базовая реализация вызывает объект функции, метод, который поддерживает только до 20 аргументов.

Вы можете перегрузить его, чтобы поддерживать больше, но я сомневаюсь в полезности такой вещи. Если у вас есть несколько источников ввода, их, вероятно, в любом случае можно рассматривать как массив.

11
ответ дан 3 December 2019 в 03:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: