Clojure未来的失败

时间:2015-08-05 12:30:54

标签: scala clojure

在Scala中,未来可能会失败,这可以异步发现:

f onComplete {
  case Success(_) => println("Great!")
  case Failure(t) => println("An error has occurred: " + t.getMessage)
}

你怎么把它翻译成Clojure?我的阅读让我相信Clojure未来/承诺模型不像Scala那样强大,你不能像这样抓住失败。那又怎么办呢?

Scala的未来永远不需要被问及它的价值 - 当它很好并且准备就绪时它会告诉你发生了什么(包括它是否失败 - 这就是这个问题的症结所在)。这就是我所说的'异步'。 Scala未来可能处于三种可能状态之一 - 未完成,完成失败,成功完成。

Scala中一个典型的用例示例是一个返回Future [T]的远程调用,其中T是您真正想要获取的类型。如果远程JVM关闭,那么在超时后将发生case Failure(t)

这是一个非常直接的模型。在问题中我要求一个简单的替代方案。作为一个侧面评论,很高兴听到Clojure打算在某个时候采用Scala Futures模型。

3 个答案:

答案 0 :(得分:1)

我记得Scala中的未来是monad所以搜索algo.monadsfluokitten以寻找合适的东西。最后我找到了Lenardo Borges' imminent库。我认为这就是你想要的。

使用此命名空间声明

(ns imminent-proof.core
  (:require [imminent.core :as i]
            [clojure.core.match :refer [match]])
  (:import  [imminent.result Success Failure]))

这是失败案例

(-> (i/future (/ 1 0))
    (i/on-complete #(match [%]
                     [{Success v}] (prn "success: " v)
                     [{Failure e}] (prn "failure: " e))))

这是成功案例

(-> (i/future (Thread/sleep 1000) 42)
    (i/on-complete #(match [%]
                     [{Success v}] (prn "success: " v)
                     [{Failure e}] (prn "failure: " e))))

这是超时案例

(-> (i/future (Thread/sleep 1000) 42)
    (i/await 500)
    (i/on-complete #(match [%]
                     [{Success v}] (prn "success: " v)
                     [{Failure e}] (prn "failure: " e))))

答案 1 :(得分:0)

我想知道Clojure是否需要特定的构造来处理失败期货的这种情况。以下行给了我相同的功能:

(defn f-cond[f func-ok func-fail] 
   (future (try (func-ok @f) (catch Exception e (func-fail e))))) 

然后:

@(f-cond (future (throw (Exception. "hi"))) 
   identity #(println "Failed: " (.getCause %)))

结果

Failed:  #<Exception java.lang.Exception: hi>

答案 2 :(得分:0)

未来的宏只是包装Java Future,而deref reader宏只是在未来调用.get()时的语法糖:


user=> (source future)
(defmacro future
  "Takes a body of expressions and yields a future object that will
  invoke the body in another thread, and will cache the result and
  return it on all subsequent calls to deref/@. If the computation has
  not yet finished, calls to deref/@ will block, unless the variant of
  deref with timeout is used. See also - realized?."
  {:added "1.1"}
  [& body] `(future-call (^{:once true} fn* [] ~@body)))
nil
user=> (source future-call)
(defn future-call 
  "Takes a function of no args and yields a future object that will
  invoke the function in another thread, and will cache the result and
  return it on all subsequent calls to deref/@. If the computation has
  not yet finished, calls to deref/@ will block, unless the variant
  of deref with timeout is used. See also - realized?."
  {:added "1.1"
   :static true}
  [f]
  (let [f (binding-conveyor-fn f)
        fut (.submit clojure.lang.Agent/soloExecutor ^Callable f)]
    (reify 
     clojure.lang.IDeref 
     (deref [] (deref-future fut))
     clojure.lang.IBlockingDeref
     (deref
      [ timeout-ms timeout-val]
      (deref-future fut timeout-ms timeout-val))
     clojure.lang.IPending
     (isRealized [] (.isDone fut))
     java.util.concurrent.Future
      (get [] (.get fut))
      (get [_ timeout unit] (.get fut timeout unit))
      (isCancelled [] (.isCancelled fut))
      (isDone [] (.isDone fut))
      (cancel [_ interrupt?] (.cancel fut interrupt?)))))
nil
user=>

因此,测试失败与java没有什么不同:你捕获ExecutionException,请参阅java doc for Future:

http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Future.html#get()

因此解决方案是从deref中捕获异常,如其他答案中所示。