2012-08-02 15 views
10

Gibt es eine einfache Möglichkeit, unnötige Argumente zu ignorieren?Wie ignoriere ich unnötige Argumente?

Zum Beispiel: (#(+ %1 %2) 1 2) kehrt 3

Ich mag würde diesen Code 3

(#(+ %1 %2) 1 2 3) 

zu Rückkehr zwingen. Aber es gibt

java.lang.IllegalArgumentException: Falsche Anzahl von Argumenten (3) geleitet zu.

Wie wird geändert ?

Ich hoffe, es gibt etwas eleganter als #(+ (nth %& 0) (nth %& 1)).

Antwort

18

Hier ist, was ich würde mit:

=> ((fn [a b & _] (+ a b)) 1 2 3) 
=> 3 

Dies schafft eine anonyme Funktion, die eine beliebige Anzahl von Argumenten entgegennimmt, sondern fügt nur die ersten beiden. Das _ Symbol tut nichts besonderes, es ist nur idiomatisch für "Ich interessiere mich nicht für dieses Ding, aber ich brauche es irgendwie gebunden". Wenn Sie denken, Sie werden dies viel zu tun, dann würden Sie wahrscheinlich definieren wollen:

(defn add-first-two 
    [a b & _] 
    (+ a b)) 

Wenn Sie wirklich in die #() Syntax sind, haben Sie %& irgendwo in der Definition für es schließen zu "erkennen", dass es eine beliebige Anzahl von Argumenten annehmen sollte. Es bedeutet nicht, dass Sie es indizieren müssten, wie Sie zeigen, es würde nur irgendwo anwesend sein müssen.Hier ein Beispiel:

=> (#(do %& (+ %1 %2)) 1 2 3) 
=> 3 

Auf der anderen Seite beinhaltet diese Lösung eine Art der Verarbeitung von %&, wo Sie eine nicht brauchen, und kann Dinge verlangsamen etwas (Ich bin nicht sicher über diese Vielleicht kann mir jemand anderes ein Feedback geben. Eine ziemlich lustige Lösung wäre, %& in einem (comment ...) Block zu stecken, der nil auswertet.

=> (#(do (comment %&) (+ %1 %2)) 1 2 3) 
=> 3 

Eine noch exotischere Lösung wäre #_... zu verwenden, die viel wie (comment...) Ausnahme ist, dass der Leser tatsächlich entfernt es aus der Auswertung, als ob man einfach nichts da getippt hatte. Auf diese Weise könnten wir es vielleicht in den Körper von (+ ...) stecken, um den Code zu verkürzen.

Was wissen Sie, es hat funktioniert. Ich habe das bisher noch nie probiert und bin ziemlich überrascht, dass es funktioniert. Offenbar gibt es einige Verarbeitung, bevor der #_... Abschnitt entfernt wird. Seltsam.

Wenn Sie nicht über eine dieser seltsamen Kommentar Lösungen mögen, und die do tut es nicht für Sie, könnten Sie innerhalb eines (if nil ...) Block setzen es immer:

=> (#(if nil %& (+ %1 %2)) 1 2 3) 
=> 3 

Nun, nach allem, , Mag ich immer noch die erste Lösung am besten (mit (fn ...)), aber einige dieser anderen sind sicherlich kürzer.

5

Dies funktioniert für eine beliebige Anzahl von Argumenten und lesbar ist:

(fn [& args] (apply + args)) 

Wenn Sie nur die ersten 2 Argumente (per Alex‘Kommentar) verwenden möchten:

(fn [& args] (apply + (take 2 args))) 

können Sie verwenden sie es direkt:

((fn [& args] (apply + (take 2 args))) 1 2) 
; => 3 

Oder binden, um die Funktion zu einem Symbol wie folgt aus:

(let [f (fn [& args] (apply + (take 2 args)))] 
    (f 1 2)) 
; => 3 

Oder erstellen var:

(def f (fn [& args] (apply + (take 2 args)))) 

Oder eine Funktion:

(defn f [& args] (apply + (take 2 args))) 

Die beste Definition für Ihren Anwendungsfall abhängt.

+2

Das summiert alle Argumente. OP fragte nach der Summe der ersten beiden, mit irgendwelchen Extras ignoriert, also müssten Sie sagen (fn [& args] (apply + (take 2 args))) – Alex

+1

das ist ein guter Punkt - aktualisiert meine Antwort. – Gert

1
user> (#(do %& (+ % %2)) 1 2) 
3 
user> (#(do %& (+ % %2)) 1 2 3) 
3 

Es ist nicht sehr elegant, aber ich denke, es ist akzeptabel.

4

Wie wäre es damit?

(#(apply + (take 2 %&)) 1 2 3 4 5) 
;; => 3