2013-05-27 46 views
10

case醫生說是否可以使用Java枚舉的Clojure案例表單?

與COND和condp,情況下,不固定時間的調度......常量表達式 所有的方式都在的情況下可以接受的。

我想受益於case的常量調度,以匹配Java枚舉。 Java的switch語句枚舉效果很好,但做以下Clojure中:在

(defn foo [x] 
    (case x 
     java.util.concurrent.TimeUnit/MILLISECONDS "yes!")) 

(foo java.util.concurrent.TimeUnit/MILLISECONDS) 

結果:IllegalArgumentException No matching clause: MILLISECONDS

正在枚舉不case支持?難道我做錯了什麼?我必須訴諸於cond還是有更好的解決方案?

回答

6

這裏的問題是case的測試常量,如文檔「必須是編譯時間文字」中所述。所以,而不是解決java.util.concurrent.TimeUnit/MILLISECONDS,字面符號'java.util.concurrent.TimeUnit/MILLISECONDS正在測試。

(foo java.util.concurrent.TimeUnit/MILLISECONDS) ; IllegalArgumentException 
(foo 'java.util.concurrent.TimeUnit/MILLISECONDS) ; yes! 

相反,解決的辦法是派遣上Enum情況下,這是Java本身編譯switch語句在枚舉什麼時候的.ordinal

(defn foo [x] 
    (case (.ordinal x) 
    2 "yes!")) 

您可以在宏包裝這個模式它可以正確評估你的案例序號:

(defmacro case-enum 
    "Like `case`, but explicitly dispatch on Java enum ordinals." 
    [e & clauses] 
    (letfn [(enum-ordinal [e] `(let [^Enum e# ~e] (.ordinal e#)))] 
    `(case ~(enum-ordinal e) 
     [email protected](concat 
      (mapcat (fn [[test result]] 
        [(eval (enum-ordinal test)) result]) 
        (partition 2 clauses)) 
      (when (odd? (count clauses)) 
      (list (last clauses))))))) 
+3

cemerick有寫起來和解決方法這在http://cemerick.com/2010/08/03/enhance-clojures-case-to-evaluate-dispatch-values/ –

+0

謝謝,你們倆!順序解決方案(我在宏中使用這種可讀性並不是問題),cemerick的解決方案運行良好。 – pron

+0

我太過分了:顯然cemerick的情況+不適用於枚舉:'(case + java.util.concurrent.TimeUnit/MINUTES java.util.concurrent.TimeUnit/MINUTES「yes!」); CompilerException java.lang.RuntimeException:不能在代碼中嵌入對象。 (但很明顯,序數解決方案確實如此) – pron

3

你可以在enumm的名字上使用一個cond

(case (.name myEnumValue) "NAME_MY_ENUM" (println "Hey, it works!"))

在我看來很簡單相比替代

+0

這個答案應該是被接受的答案。它保持'case'的恆定時間性能並保留'Enum'的語義。它確實會失去編譯時檢查'Enum',但編譯時檢查通常在Clojure中進行交易以獲得其他好處。 – Jason

+0

謝謝傑森:D –

0

這裏只是用平等的情況下,檢查簡單的解決方案 -

(defn cases [v & args] 
    (let [clauses (partition 2 2 args)] 
    (some #(when (= (first %) v) (second %)) clauses))) 

=> (cases EventType/received EventType/send "A" EventType/received "B") 
=> "B" 
+0

這不是一個恆定時間的操作。這個問題需要一個恆定時間的解決方案。 – pron