2010-04-29 5 views
11

Es scheint eine Grenze für die Anzahl der Parameter zu geben, die eine Clojure-Funktion annehmen kann.Warum gibt es ein Limit von maximal 20 Parametern für eine Clojure-Funktion

Wenn eine Funktion mit mehr als 20 Parameter definiert, erhalte ich folgendes:

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

Offensichtlich kann dies vermieden werden, aber ich war Schlagen diese Grenze das Ausführungsmodell eines bestehenden DSL clojure Portierung und ich habe Konstrukte in meinem DSL wie die folgenden, die durch Makroerweiterung kann ganz einfach auf Funktionen zugeordnet werden, außer für diese Grenze:

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

, die eine DSL-Anweisung ist ein neuronales Netz zu nennen mit 90 Eingangsknoten Kann natürlich umgehen, aber ich frage mich, wo das Limit herkommt. Danke.

+0

Gerade als für Interesse Hinweis auf Stil: Steve McConnell „Code Complete“ befürwortet, teilweise Programmiereffizienz Studien basierend auf, dass ein Verfahren soll nie mehr als 7 Argumente hat, und in jüngerer Zeit Robert C. Martin „Clean Code“ setzt das Limit so niedrig wie 3. Ich habe 7 eine gute Faustregel für die Entscheidung, wann ein Interface neu zu konstruieren, gefunden, während 3 scheint ein bisschen extrem. Ja, mir sind Ihre besonderen Umstände mit dem Makro und allem bekannt. Ich weise nur darauf hin, dass 20 für den "allgemeinen" Fall ziemlich großzügig ist. Erstellen Sie Ihre Neuronen mit Arrays oder etwas –

+0

und führen sie die Funktion als ASTA. Und Karte-reduzieren die Seqs? Etwas wie das? http://www.fatvat.co.uk/2009/06/back-propagation-algorithm-in-clojure.html – claj

Antwort

17

Zunächst gilt das Limit nur für erforderliche Positionsargumente; Sie können immer die Variable arity Fall (& more-args in der Signatur der Funktion) verwenden, wie viele Argumente zu behandeln, wie Sie wollen:

(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 

In der Tat, auf den ersten Blick ist & args wahrscheinlich genau die richtige Lösung sein, um Ihre Problem. (ZB können Sie eine Funktion über Ihre Eingangsknoten abbilden, die in einer Sequenz, loop/recur über die Sequenz usw. gesammelt wurden.) - tendiert dazu, bei einer großen Anzahl von ähnlichen Elementen mehr Sinn zu geben, als jedem einzelnen Namen zuzuweisen

(Bitte beachten Sie, dass ich nicht vorschlage, die Art der spezifischen DSL, die Sie in Clojure transkribieren, oder die Art von Problemen, mit denen Sie zu tun haben, nur Punkte, die für Sie von Interesse sein könnten, zu kennen. Wenn Sie eine wirklich flippige Situation haben, in der dies nicht zutrifft, können Sie vielleicht weitere Details angeben und wir werden sehen, ob hier jemand nützliche Tipps zum Umgang mit ihm in Clojure anbieten kann.)

Für Der Vollständigkeit halber können Sie diehinzufügenBit auf eine Funktion, die ihre ersten 19 Argumente wie erforderlich Positions args nimmt:

(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 

Beachten Sie, dass, wenn Sie 20 Positions args angeben und die & arg obendrein wird offenbar Seltsamkeit erfolgen.

Was die Begründung, ich glaube, dass dies mit der Tatsache zu tun hat, dass der JVM auf ein Verfahren durch arity sehr effizient versenden kann, so dass die clojure.lang.Fn Klasse die invoke Methode für arities bis zu 20 überlastet hat Ich bin nicht ganz sicher, ob es höher gehen könnte, aber ich nehme an, das ist nicht etwas, was die Leute so oft brauchen ... Ich meine, ich finde sicherlich eine API, die über 20 Positionsargumente zu einer etwas verdächtigen Funktion spezifiziert.

+0

Danke & args richtet sie in der Tat perfekt. – GuyC

+2

Nur eine Notiz re: 20 Positions args mit und args zugleich sein: es ist ein Fehler war, die verursacht 'nil' ohne den Körper für diese arity ausgewertet wird die Funktion zurückgegeben werden, die Reiche vor ein paar Minuten festgelegt hat. Daher wird 1.2 dieses Problem nicht haben. –

11

Die Antwort von Michal Marczyk sagt Ihnen sehr gut, wie Sie das Limit umgehen können. Wenn Sie an dem Grund dieser Einschränkung interessiert sind, möchten Sie vielleicht einen Blick auf dieses Bit clojure Quelle werfen: IFn

aufrufen, ein Java überladen Methode implementiert von der Ifn-Schnittstelle, reich überladen es zu unterstützen 20 Argumente. Wenn Sie eine Funktion in clojure aufrufen, ruft die zugrunde liegende Implementierung Aufrufe für das Funktionsobjekt auf, eine Methode, die nur bis zu 20 Argumente unterstützt.

Sie könnten es mehr Unterstützung überlasten, aber ich bezweifle, von der Nützlichkeit einer solchen Sache. Wenn Sie eine Reihe von Eingabequellen haben, können diese trotzdem als Array behandelt werden.

+0

Michals Antwort bringt mich ans Limit, aber auch interessant, IFn zu sehen. Vielen Dank. – GuyC

Verwandte Themen