Clojure中的合并条件参数(CL样式)

Clojure中的合并条件参数(CL样式),clojure,lisp,conditional,common-lisp,Clojure,Lisp,Conditional,Common Lisp,在Clojure,我这样做 (println (cond false "don't care" "otherwise" "otherwise")) 在公共LISP中,这将是 (print (cond (nil "don't care") ("otherwise") )) 有没有办法在Clojure中获得这种简化的cond?我相信Clojure版本的目的是减少参数。您当然可以编写自己的cond-ish宏来执行您想要的操作 这里是一个简单的实现(即不实现完整的CL版本) 然后你就可以 (my-c

在Clojure,我这样做

(println (cond false "don't care" "otherwise" "otherwise"))
在公共LISP中,这将是

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

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

我相信Clojure版本的目的是减少参数。您当然可以编写自己的cond-ish宏来执行您想要的操作

这里是一个简单的实现(即不实现完整的CL版本)

然后你就可以

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

包含Alex Taggart在下面注意到的修复程序的版本。通过测试中显示的所有测试用例。它允许传递给
my cond
的任意子句的长度为1,而不是2,这导致长度为1的子句既是对真实性的测试,也是对真实性的结果。基于我对CL的有限经验,我认为这种行为与
cond
的行为不同,但似乎与我对您要求的解释一致。科塔拉克的回答似乎与CL one一致,因为在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"

CL
cond
的一个重要特性是,如果
cond
的任何操作数是单态,则对单态内的元素求值,如果该值为非nil,则返回该值而不进行第二次求值

(续)
(a 100)
((f 1 2 3))
(b)(200)
如果
a
为真,则此表单的计算结果为100;如果
(f 1 2 3)
的值为非零,则此表单的计算结果为100;如果
b
为非零,则此表单的计算结果为200;如果
为非零,则此表单的计算结果为
的值

我相信你需要的是以下几点

(定义宏我的条件[[if1&then1]&其他]
(当(或如果是其他)
(让[附加条款#(如果其他`(cl cond~@others))]
(如有的话)1
`(如果~if1(do~@then1)~extra子句#)
`(或~if1~附加条款#####(###)))

惯用用法是:(println(cond false“don't care”:else“other”))。你为什么想要CL版本?简短回答-将CL翻译成Clojure。对于同样返回结果的真理测试,有一个10行语句似乎是惯用的CL。(即合并)。常见的Lisp表单并不像您预期的那样工作。Svante,怎么会这样?如果
false
为false,则返回“不在乎”,否则返回“否则”。你认为鹰眼期望什么?我真正想要的是(我的条件(假1)(假2)(3));结果在3中使用解构的问题是,您无法区分缺勤和无,这在本例中很重要。例如,
(我的cond(:else nil))
应该返回nil。感谢您指出这一点。我添加了一个版本来处理这个问题。实际上,我认为我在解释hawkeye的问题时已经走得太远了,允许CL版本中的单元素形式出现在任何地方,而不是像else子句一样。但我还是要让它保持现状。在尝试此操作之前,可能应该在CL repl中使用。此版本的my cond有一个bug,在某些情况下,它会对if1部分进行两次评估。所以副作用会发生两次。cond的CL版本确保在这种情况下副作用只发生一次。
(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"