3

在带有clojure 1.5.1的lighttable下使用rxjava(http://netflix.github.io/RxJava/javadoc/),考虑以下(使用副作用,变异(可怕!)外部收集器从monad中提取数据)

(ns expt1.core (:import [rx]))

(def ^:private collector (atom []))
(defn- collect [item]
  (reset! collector (conj @collector item)))

(def string-explode (partial map identity))

(reset! collector [])
(->
 (Observable/toObservable ["one" "two" "three"])
 (.mapMany #(Observable/toObservable (string-explode %)))
 (.subscribe collect)
 )

@collector

产生:

[\o \n \e \t \w \o \t \h \r \e \e]

我想说

(reset! collector [])
(->
 (Observable/toObservable ["one" "two" "three"])
 (.mapMany (comp Observable/toObservable string-explode))
 (.subscribe collect)
 )

但是,惊喜

clojure.lang.Compiler$CompilerException: java.lang.RuntimeException: Unable to find static field: toObservable in class rx.Observable, compiling:(NO_SOURCE_PATH:93:1)
             Compiler.java:6380 clojure.lang.Compiler.analyze
             Compiler.java:6322 clojure.lang.Compiler.analyze
             Compiler.java:3624 clojure.lang.Compiler$InvokeExpr.parse
             Compiler.java:6562 clojure.lang.Compiler.analyzeSeq
             ...

事实上,只是

Observable/toObservable

产生类似的异常。为什么 Clojure 可以Observable/toObservable在表达式中找到它

#(Observable/toObservable (string-explode %))

但不是像这样的表达

(comp Observable/toObservable string-explode)

?

4

1 回答 1

4

Observable/toObservable是 Java 方法,而不是 Clojure 函数。您不能将 Java 方法视为函数值,就像使用 Clojure 函数一样。comp组成 Clojure 函数(实现IFn接口的对象)。解决方案:将方法调用包装在 Clojure 函数中。

另一件事:

(defn- collect [item]
  (reset! collector (conj @collector item)))

应该:

(defn- collect [item]
  (swap! collector conj item)))

reset!当您不想使用旧值时才在原子上使用。当你这样做时,使用swap!,否则不能保证原子更新(另一个线程可以在你读取它的值后更新原子)。

于 2013-05-30T19:34:21.127 回答