在Clojure中我这样做
(println (cond false "don't care" "otherwise" "otherwise"))
在共同的LISP中,这将是
(print (cond (nil "don't care") ("otherwise") ))
有没有办法在Clojure中获得这种简化的cond
?
答案 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#)))))