Clojure中的合并cond参数(CL风格)

时间:2010-11-08 23:03:27

标签: clojure lisp conditional common-lisp

在Clojure中我这样做

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

在共同的LISP中,这将是

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

有没有办法在Clojure中获得这种简化的cond

3 个答案:

答案 0 :(得分: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 ~@more#))
          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 ~@others))]
      (if then1
        `(if ~if1 ~then1 ~extra-clauses#)
        `(if ~if1 ~if1  ~extra-clauses#)))))

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

答案 1 :(得分:0)

我认为clojure版本的目的是减少parens。你当然可以编写自己的cond-ish宏来做你想做的事。

这是一个简单的实现(即没有实现完整的CL版本)......

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

然后你可以......

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

答案 2 :(得分:0)

CL cond的一个重要特征是,如果cond的任何操作数是单例,则对singelton中的元素进行求值,如果该值不为nil,则它为null。返回而没有第二次评估。

(cond
   (a 100)
   ((f 1 2 3))
   (b 200))

如果a为true,则此表单的值为100;如果非零,则为(f 1 2 3)的值;如果b为非null,则该值为200。 nil

我相信您需要的是以下物品。

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