2010-11-26 51 views
11

我想創建一個函數,它需要一個必需的參數x,以及一個可選參數opt1或一個關鍵字參數opt2。Clojure關鍵字和可選參數問題

現在我有

(defn foo x & [opt1 {:keys [opt2]}] 
    ... 

但上面的簽名只讓我傳遞關鍵字參數OPT2當x和OPT1存在像

(foo 'x 'opt1 {:opt2 'opt2}) 

不喜歡這個

(foo 'x {:opt2 'opt2}) 

請幫我創建一個函數,它需要一個必需的參數X和opt1或opt2,whe re opt2是一個關鍵字參數。

謝謝。

編輯:我也想爲其他宏做同樣的事情。所以我仍然需要使用defmacro。

+0

考慮使用`從[clojure.contrib.def] defnk`(http://richhickey.github.com/clojure-contrib/def-api.html)代替顯式解構。 – ffriend 2010-11-26 20:15:48

回答

15

問題不明確。考慮一個函數(fn foo [x y & args]),它接受兩個可選參數,然後是任意數量的關鍵字參數。如果你把它叫做(foo :bar :baz),你的程序如何處理它? x =>:bary =>:baz?或者xy沒有提供,只有一個:bar =>:baz關鍵字參數?

即使在Common Lisp中,在解析函數參數方面比Clojure更具靈活性,至少根據one popular book推薦混合可選參數和關鍵字參數。

最好的辦法是將所有的參數改爲位置參數,或者將所有參數改爲關鍵字參數。如果使用關鍵字參數,則可以使用散列映射解構來爲「可選」關鍵字參數提供默認值。

user> (defn foo [& {:keys [x y bar] 
        :or {x 1 y 2 bar 3}}] 
     (prn [x y bar])) 
#'user/foo 
user> (foo) 
[1 2 3] 
nil 
user> (foo :bar :baz) 
[1 2 :baz] 
nil 
2

你必須檢查aditional的參數是關鍵字參數或不反正(我假定你或者是異或)這樣你就可以做這樣的:

(defn foo [& args] 
    (if (= (count args) 1) 
     (let [[opt1] args] (println opt1)) 
     (let [{:keys [opt2]} args] (println opt2)))) 

檢查參數,如果他們是關鍵詞參數與否。由於您只有一個可選參數,所以很容易:檢查是否只有一個關鍵字參數需要兩個參數。