来自clojure.java.api.Clojure的意外行为

时间:2014-12-15 10:39:18

标签: java api clojure conditional

我一直在尝试使用 Clojure 1.6.0 中引入的clojure.java.api,因为我想将一些Clojure功能导入到我的java项目中。不幸的是,当我从Java调用条件函数以及时,它的表现并不像我所期望的那样。

IFn and = Clojure.var("clojure.core", "and");
IFn or = Clojure.var("clojure.core", "or");

-- equivalent to (and true false) in clojure
and.invoke(true,false); --> returns true rather than false???   

-- equivalent to (or true false) in clojure
or.invoke(true,false); --> returns null rather than true???

-- equivalent to (and true true) in clojure
and.invoke(true,true); --> returns true as expected

-- equivalent to (or true true) in clojure    
or.invoke(true,true); --> returns null rather than true???

我无法相信这是一个错误,所以我怀疑我错过了与API相关的相关基础知识。不管是什么原因,它让我感到很困惑。如果有人能提供解释,我将非常感激。

谢谢,

2 个答案:

答案 0 :(得分:3)

andor是宏,评估规则对它们有些不同。例如,在Clojure REPL上,尝试评估and抛出CompilerException java.lang.RuntimeException: Can't take value of a macro: #'clojure.core/and, compiling:(NO_SOURCE_PATH:0:0)

虽然应该有一种方法可以通过clojure.java.api.Clojure使用它们,但我现在还没有想到它,因为需要编译宏才能工作。

我能想到的下一个最佳选择是使用eval,但我不确定您是否想要这样做。另一方面,为什么在存在良好的旧and / or Java运算符时使用&& / ||

答案 1 :(得分:1)

andor是宏,而不是函数。他们期望两个或更多表单(我认为这是一个符号的clojure.lang.IPersistentList或嵌套的IPersistentLists),它们会扩展为let*if的组合。

(clojure.walk/macroexpand-all '(and true false))
;returns:
(let* [and__3941__auto__ true] 
      (if and__3941__auto__ 
        false
        and__3941__auto__))

你可能最好做一个代表你使用andor的clojure fn。例如,将它们带到一个集合上:

(defn reduce-and [values]
  (reduce #(and %1 %2) values))
(defn reduce-or [values]
  (reduce #(or %1 %2) values))