2014-12-15 3 views
3

Я экспериментировал с clojure.java.api введен в Clojure 1.6.0, как я хотел бы импортировать некоторые функциональные возможности Clojure в мой проект Java. К сожалению, он не ведет себя так, как я ожидал бы при вызове условных функций и и или с Java.Неожиданное поведение от clojure.java.api.Clojure

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 отсутствую. Какая бы ни была причина, это оставило меня довольно смущенным. Если кто-нибудь может предложить объяснение, я был бы очень благодарен.

Thanks,

Мэтт.

ответ

3

and и or - это макросы, а правила для оценки для них несколько разные. Например, когда на Clojure REPL, пытаясь оценить and throws 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

and и or - это макросы, а не функции. Они ожидают две или более формы (так, например, clojure.lang.IPsistentList символов или вложенных IPersistentLists), которые они расширяют в комбинацию из let* и if.

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

Вы можете быть лучше сделать Clojure Fn, которая использует and и or от вашего имени. Например, взять их по коллекции:

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

Примите во внимание, что 'сокращения-and' и' сокращения-or' расслабить короткое замыкание семантику исходного 'or' и' and', который на что вы иногда рассчитываете. –

Смежные вопросы