Clojure。 Intellij。延迟。同时。从头开始的 Clojure

Clojure. Intellij. Delay. Concurrent. Clojure from the Ground Up

我正在尝试解决 Clojure From the Ground Up 第 6 章末尾的练习。 这是我遇到的第一个问题...

  (defn sum [start end] (delay (reduce + (range start end))))  ;; Define sum.
=> #'chapter6.core/sum

  (time (sum 0 1e7))  ;; Start sum but it delays, so almost no time elapses.
"Elapsed time: 0.2808 msecs"
=> #object[clojure.lang.Delay 0x2656db01 {:status :pending, :val nil}]

  (deref sum)  ;; Ask for the result. This should take some time. Only it doesn't. It errors right away.

Execution error (ClassCastException) at chapter6.core/eval1595 (form-init10872915734268438705.clj:1).
class chapter6.core$sum cannot be cast to class java.util.concurrent.Future (chapter6.core$sum is in unnamed module of loader cloju-re.lang.DynamicClassLoader @7c650722; java.util.concurrent.Future is in module java.base of loader 'bootstrap')

我是新来的。我对 "bootstrap" 或 "module" 或... 我究竟做错了什么?先感谢您。 顺便说一句,练习是否有“...从头开始”的答案?

成功:

(deref (sum 0 1e7))

您的函数仅 returns 延迟 调用时 。在 (deref sum) 中,没有任何东西调用它(事实上,你永远不会提供参数值将强制包含 were 它调用)。相反,您尝试取消引用函数 sum 本身,这是非法的,因为函数不是延迟。

创建项目比在 REPL 中 运行 更容易看到细节。考虑将您的代码添加到 this template project:

(ns tst.demo.core
  (:use tupelo.core tupelo.test)
  (:require [tupelo.misc :as misc]))

(defn sum
  [start end]
  (delay (reduce + (range start end))))  ;; Define sum.

(dotest
  (time (sum 0 1e7)) ;; Start sum but it delays, so almost no time elapses.
  (let [delay-val (sum 0 1e7)] ; sum returns a delay
    (spyxx delay-val)               ; print name & type of `delay-val`
    (time (deref delay-val))        ; `deref` forces the computation of the sum
    (spyxx (deref delay-val))       ; print expression & type
    ))

结果:

-------------------------------
   Clojure 1.10.1    Java 13
-------------------------------

Testing tst.demo.core

"Elapsed time: 0.140221 msecs"      ; from first `time`
delay-val => <#clojure.lang.Delay #object[clojure.lang.Delay 0x455cd186 {:status :pending, :val nil}]>

"Elapsed time: 189.021064 msecs"    ; from 2nd `time`
(deref delay-val) => <#java.lang.Long 49999995000000>  

还有更多文档 in the README and the API docs


尝试添加:

(spyxx sum)

产生:

sum => <#tst.demo.core$sum #object[tst.demo.core$sum 0x539edd3 "tst.demo.core$sum@539edd3"]>

这就是Clojure如何"prints"函数的值。


如果您犯了一个错误,您可以在错误消息中得到一个行号,这对您有很大帮助。取消引用一个函数是不合法的,所以我们得到一个错误:

(deref sum)   ; on line #17 of my file

产生:


ERROR in (dotest-line-9) (core.clj:2298)
Uncaught exception, not in assertion.
expected: nil
  actual: java.lang.ClassCastException: class tst.demo.core$sum cannot be cast to class java.util.concurrent.Future (tst.demo.core$sum is in unnamed module of loader clojure.lang.DynamicClassLoader @67af3485; java.util.concurrent.Future is in module java.base of loader 'bootstrap')
 at clojure.core$deref_future.invokeStatic (core.clj:2298)
    clojure.core$deref.invokeStatic (core.clj:2320)
    clojure.core$deref.invoke (core.clj:2306)
    tst.demo.core$fn__21007.invokeStatic (core.clj:17) # ***** error line number *****
    tst.demo.core/fn (core.clj:9)
    clojure.test$test_var$fn__9737.invoke (test.clj:717)
    clojure.test$test_var.invokeStatic (test.clj:717)
    <...snip...>



更新

不要忘记在 project.clj 下的 :dependencies:

中包含此行
 [tupelo "0.9.198"]

有关示例,请参阅 this template project