2010-11-08 87 views
2

在Clojure中我做到這一點Clojure中(CL風格)合併COND參數

(println (cond false "don't care" "otherwise" "otherwise")) 

Common Lisp中,這將是

(print (cond (nil "don't care") ("otherwise"))) 

是否有一種方式來獲得這種簡化cond用Clojure ?

+2

成語是:(的println(條件假 「不關心」:別人 「否則」))。你爲什麼想要CL版本? – nickik 2010-11-09 00:42:25

+0

簡短的回答 - 將CL翻譯成Clojure。對於真相測驗,有一條10行的陳述似乎是習慣性的CL,*也*返回結果。 (即合併)。 – hawkeye 2010-11-09 02:13:36

+0

Common Lisp表單不能像你期望的那樣工作。 – Svante 2010-11-09 10:44:12

回答

1

版,其中包括一個修復Alex Taggart在下面注意到。通過測試中顯示的所有測試用例。它允許傳遞給my-cond的任意子句長度爲1而不是2,這導致長度爲1的子句既是對真實性的測試,也是對真實性的測試結果。根據我對CL的有限經驗,我實際上認爲這種行爲與cond的行爲不同,但似乎符合我如何解釋你所要求的內容。 Kotarak的答案似乎與CL一致,因爲使用CL cond中的最後一個語句似乎與使用Clojure版本中的:else子句匹配。

不管這裏是一個解決方案,它應該允許任何子句的長度爲1,並將其用於真值測試和結果。

(defmacro my-cond 
    [& others] 
    (if others 
    (let [more# (next others) 
      extra-clauses# (if more# `(my-cond [email protected]#)) 
      clause# (first others)] 
     (if (= 2 (count clause#)) 
     `(if ~(first clause#) ~(second clause#) ~extra-clauses#) 
     `(if ~(first clause#) ~(first clause#) ~extra-clauses#))))) 


(deftest my-cond-works 
    (is (= 3 (my-cond (false 1) (false 2) (3)))) 
    (is (= "otherwise" (my-cond (false "don't care") ("otherwise")))) 
    (is (= nil (my-cond (:one nil) ("otherwise")))) 
    (is (= "care" (my-cond (1 "care") ("otherwise")))) 
    (is (= "otherwise" (my-cond (false "care") ("otherwise") (true "true")))) 
    (is (= "silly" (my-cond (nil "no") (nil) ("yes" "silly"))))) 

我真的建議在翻譯CL到cond Clojure的形式。我將把CL語法與Clojure語法一起放在同一個項目中,因爲現在不值得節省時間翻譯它。在習慣了Clojure的cond並試圖記住爲什麼其他語法存在之後,在將來查看代碼似乎不值得通過不翻譯節省的時間。

下面的版本失敗,因爲下面的Alex Taggart說。保持在這裏,所以他的評論是有道理的。 以下版本的功能:

(defmacro my-cond [[if1 then1] & others] 
    (when (or if1 then1 others) 
    (let [extra-clauses# (if others `(my-cond [email protected]))] 
     (if then1 
     `(if ~if1 ~then1 ~extra-clauses#) 
     `(if ~if1 ~if1 ~extra-clauses#))))) 

user> (my-cond (false "first") (nil nil) ("otherwise")) 
"otherwise" 
+0

使用解構的問題在於,在這種情況下,失去區分「缺席」和「無」的能力。例如,'(my-cond(:else nil))'應該返回nil。 – 2010-11-09 05:45:36

+0

感謝您指出這一點。我已經添加了一個處理這個問題的版本。實際上,我認爲我已經解釋了hawkeye的要求,它允許CL版本中的單元素形式位於任何位置,而不僅僅是else子句。儘管如此,它會離開它。嘗試這個之前,可能應該在CL repl中玩過。 – 2010-11-09 17:50:40

0

我相信clojure版本的意圖是減少parens。你當然可以編寫自己的cond-ish宏來做你想做的事情。

下面是一個簡單的實現(即未實現充分CL版)...

(defmacro my-cond [[if1 then1] & others] 
    (if others 
    `(if ~if1 ~then1 (my-cond [email protected])) 
    `(if ~if1 ~then1))) 

然後你可以...

(my-cond (false 1) (false 2) (3 3)) ; results in 3 
+0

我真正想要的是(my-cond(false 1)(false 2)(3));結果爲3 – hawkeye 2010-11-09 02:11:42