2013-08-26 12 views
7

Ich bin ein Neuling auf Clojure und ich frage mich, ob es einen Weg gibt, eine Funktion zu definieren, die so genannt werden kann:Variadische Funktion mit Schlüsselwort-Argumente

(strange-adder 1 2 3 :strange true) 

Das heißt, eine Funktion, die empfangen können eine variable Anzahl von Ints und ein Schlüsselwortargument.

Ich weiß, dass ich eine Funktion mit Schlüsselwort-Argumente auf diese Weise definieren:

(defn strange-adder 
    [a b c & {:keys [strange]}] 
    (println strange) 
    (+ a b c)) 

Aber jetzt kann meine Funktion nur eine feste Anzahl von Ints erhalten.

Gibt es eine Möglichkeit, beide Stile gleichzeitig zu verwenden?

Antwort

8

leider nicht.

Der Destrukturierungsoperator & verwendet alles danach auf der Argumentliste, so dass er nicht in der Lage ist, zwei verschiedene Gruppen von Gruppen mit variabler Arity-Destrukturierung in einer Form zu behandeln.

Eine Möglichkeit besteht darin, die Funktion in mehrere Aritäten aufzuteilen. Obwohl dies nur funktioniert, wenn Sie es arrangieren können, so ist nur einer von ihnen variadic (verwendet &). Eine universellere und weniger bequeme Lösung besteht darin, die gesamte Argumentliste als eine variadische Form zu behandeln und die Zahlen von Anfang an manuell auszuwählen.

user> (defn strange-adder 
     [& args] 
     (let [nums (take-while number? args) 
       opts (apply hash-map (drop-while number? args)) 
       strange (:strange opts)] 
      (println strange) 
       (apply + nums))) 
#'user/strange-adder 
user> (strange-adder 1 2 3 4 :strange 4) 
4 
10 
1

Es gibt keine formelle Unterstützung, die ich kenne, aber so etwas wie dies sollte machbar sein:

(defn strange-adder 
    [& args] 
    (if (#{:strange} (-> args butlast last)) 
    (do (println (last args)) 
     (apply + (drop-last 2 args))) 
    (apply + args))) 

Ich weiß nicht, ob dies verallgemeinert werden kann (Prüfung auf Schlüsselwörter wie erweitern zu einer beliebigen Anzahl von abschließenden Argumenten?). Eine Option könnte darin bestehen, alle Optionen in eine hashmap als letztes Argument zu setzen und zu überprüfen, ob das letzte Argument eine hashmap ist (aber dies würde bei einigen Funktionen nicht funktionieren, die beliebige Argumente erwarten, die hashmaps sein könnten).

4

Bewegen Sie den variadische Abschnitt mit dem Schwanz der Argumentliste und die Optionen als eine Karte übergeben:

(defn strange-adder [{:keys [strange]} & nums] 
    (println strange) 
    (apply + nums)) 

(strange-adder {:strange true} 1 2 3 4 5)