2013-08-26 98 views
7

我是一個新手,Clojure的,我想知道如果有一種方法來定義可以這樣調用函數:與關鍵字參數可變參數功能

(strange-adder 1 2 3 :strange true) 

也就是說,一個函數,它可以接收可變數量的整數和關鍵字參數。

我知道我可以定義關鍵字參數的函數是這樣的:

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

但現在我的功能只能接收整數的固定數量。

有沒有辦法同時使用兩種樣式?

回答

8

不幸的是,沒有。

解構運算符&在參數列表中使用後面的所有內容,因此它無法處理一個形式的兩組不同的變量解構組。

一種選擇是將功能分成幾個部分。雖然這隻適用於你可以安排它,所以只有其中一個是可變的(使用&)。更普遍和不太方便的解決方案是將整個參數列表視爲一個可變參數,並從手動開始選擇數字。

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

沒有正式的支持,我知道的,但這樣的事情應該是可行的:

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

我不知道這是否可以推廣(檢查關鍵字如何擴大到任意數量的最終參數?)。一種選擇可能是將所有選項放在散列表中作爲最後一個參數,並檢查最後一個參數是否爲散列表(但對於某些函數來說,這些函數可能會是hashmaps的任意參數)。

4

移動可變參數部分到參數列表的尾部,並傳遞選項作爲地圖:

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

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