如何阅读 clojure 堆栈跟踪?

How to read clojure stack trace?

我尝试了一些 clojure 教程。我将依赖项部分复制到我的 project.clj。我犯了一个错误。我放了“1.7.0”而不是“1.6.0”版本的 clojure。您可以在此处查看全部 'dependencies':

:dependencies [[org.clojure/clojure "1.7.0"]
                 [org.clojure/core.async "0.1.346.0-17112a-alpha"]

                 [compojure "1.3.1"]

                 [ring/ring-core "1.3.2" :exclusions [javax.servlet/servlet-api]]
                 [ring/ring-servlet "1.3.2" :exclusions [javax.servlet/servlet-api]]
                 [ring/ring-defaults "0.1.2" :exclusions [javax.servlet/servlet-api]]

                 [cc.qbits/jet "0.5.4"]]

由于这个错误,我在 'lein run' 之后得到了这个:

Exception in thread "main" clojure.lang.ArityException: Wrong number of args (2) passed to: StringReader, compiling:(abnf.clj:189:28)
    at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:3628)
    at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:3622)
    at clojure.lang.Compiler$DefExpr.eval(Compiler.java:439)
    at clojure.lang.Compiler.eval(Compiler.java:6787)
    at clojure.lang.Compiler.load(Compiler.java:7227)
    at clojure.lang.RT.loadResourceScript(RT.java:371)
    at clojure.lang.RT.loadResourceScript(RT.java:362)
    at clojure.lang.RT.load(RT.java:446)
    at clojure.lang.RT.load(RT.java:412)
    at clojure.core$load$fn__5448.invoke(core.clj:5866)
    at clojure.core$load.doInvoke(core.clj:5865)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at clojure.core$load_one.invoke(core.clj:5671)
    at clojure.core$load_lib$fn__5397.invoke(core.clj:5711)
    at clojure.core$load_lib.doInvoke(core.clj:5710)
    at clojure.lang.RestFn.applyTo(RestFn.java:142)
    at clojure.core$apply.invoke(core.clj:632)
    at clojure.core$load_libs.doInvoke(core.clj:5749)
    at clojure.lang.RestFn.applyTo(RestFn.java:137)
    at clojure.core$apply.invoke(core.clj:632)
    at clojure.core$require.doInvoke(core.clj:5832)
    at clojure.lang.RestFn.invoke(RestFn.java:805)
    at instaparse.core$eval9510$loading__5340__auto____9511.invoke(core.clj:1)
    at instaparse.core$eval9510.invoke(core.clj:1)
    at clojure.lang.Compiler.eval(Compiler.java:6782)
    at clojure.lang.Compiler.eval(Compiler.java:6771)
    at clojure.lang.Compiler.load(Compiler.java:7227)
    at clojure.lang.RT.loadResourceScript(RT.java:371)
    at clojure.lang.RT.loadResourceScript(RT.java:362)
    at clojure.lang.RT.load(RT.java:446)
    at clojure.lang.RT.load(RT.java:412)
    at clojure.core$load$fn__5448.invoke(core.clj:5866)
    at clojure.core$load.doInvoke(core.clj:5865)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at clojure.core$load_one.invoke(core.clj:5671)
    at clojure.core$load_lib$fn__5397.invoke(core.clj:5711)
    at clojure.core$load_lib.doInvoke(core.clj:5710)
    at clojure.lang.RestFn.applyTo(RestFn.java:142)
    at clojure.core$apply.invoke(core.clj:632)
    at clojure.core$load_libs.doInvoke(core.clj:5749)
    at clojure.lang.RestFn.applyTo(RestFn.java:137)
    at clojure.core$apply.invoke(core.clj:632)
    at clojure.core$require.doInvoke(core.clj:5832)
    at clojure.lang.RestFn.invoke(RestFn.java:436)
    at clout.core$eval9504$loading__5340__auto____9505.invoke(core.clj:1)
    at clout.core$eval9504.invoke(core.clj:1)
    at clojure.lang.Compiler.eval(Compiler.java:6782)
    at clojure.lang.Compiler.eval(Compiler.java:6771)
    at clojure.lang.Compiler.load(Compiler.java:7227)
    at clojure.lang.RT.loadResourceScript(RT.java:371)
    at clojure.lang.RT.loadResourceScript(RT.java:362)
    at clojure.lang.RT.load(RT.java:446)
    at clojure.lang.RT.load(RT.java:412)
    at clojure.core$load$fn__5448.invoke(core.clj:5866)
    at clojure.core$load.doInvoke(core.clj:5865)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at clojure.core$load_one.invoke(core.clj:5671)
    at clojure.core$load_lib$fn__5397.invoke(core.clj:5711)
    at clojure.core$load_lib.doInvoke(core.clj:5710)
    at clojure.lang.RestFn.applyTo(RestFn.java:142)
    at clojure.core$apply.invoke(core.clj:632)
    at clojure.core$load_libs.doInvoke(core.clj:5749)
    at clojure.lang.RestFn.applyTo(RestFn.java:137)
    at clojure.core$apply.invoke(core.clj:632)
    at clojure.core$require.doInvoke(core.clj:5832)
    at clojure.lang.RestFn.invoke(RestFn.java:482)
    at compojure.core$eval9322$loading__5340__auto____9323.invoke(core.clj:1)
    at compojure.core$eval9322.invoke(core.clj:1)
    at clojure.lang.Compiler.eval(Compiler.java:6782)
    at clojure.lang.Compiler.eval(Compiler.java:6771)
    at clojure.lang.Compiler.load(Compiler.java:7227)
    at clojure.lang.RT.loadResourceScript(RT.java:371)
    at clojure.lang.RT.loadResourceScript(RT.java:362)
    at clojure.lang.RT.load(RT.java:446)
    at clojure.lang.RT.load(RT.java:412)
    at clojure.core$load$fn__5448.invoke(core.clj:5866)
    at clojure.core$load.doInvoke(core.clj:5865)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at clojure.core$load_one.invoke(core.clj:5671)
    at clojure.core$load_lib$fn__5397.invoke(core.clj:5711)
    at clojure.core$load_lib.doInvoke(core.clj:5710)
    at clojure.lang.RestFn.applyTo(RestFn.java:142)
    at clojure.core$apply.invoke(core.clj:632)
    at clojure.core$load_libs.doInvoke(core.clj:5749)
    at clojure.lang.RestFn.applyTo(RestFn.java:137)
    at clojure.core$apply.invoke(core.clj:632)
    at clojure.core$require.doInvoke(core.clj:5832)
    at clojure.lang.RestFn.invoke(RestFn.java:512)
    at server.core$eval20$loading__5340__auto____21.invoke(core.clj:1)
    at server.core$eval20.invoke(core.clj:1)
    at clojure.lang.Compiler.eval(Compiler.java:6782)
    at clojure.lang.Compiler.eval(Compiler.java:6771)
    at clojure.lang.Compiler.load(Compiler.java:7227)
    at clojure.lang.RT.loadResourceScript(RT.java:371)
    at clojure.lang.RT.loadResourceScript(RT.java:362)
    at clojure.lang.RT.load(RT.java:446)
    at clojure.lang.RT.load(RT.java:412)
    at clojure.core$load$fn__5448.invoke(core.clj:5866)
    at clojure.core$load.doInvoke(core.clj:5865)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at clojure.core$load_one.invoke(core.clj:5671)
    at clojure.core$load_lib$fn__5397.invoke(core.clj:5711)
    at clojure.core$load_lib.doInvoke(core.clj:5710)
    at clojure.lang.RestFn.applyTo(RestFn.java:142)
    at clojure.core$apply.invoke(core.clj:632)
    at clojure.core$load_libs.doInvoke(core.clj:5749)
    at clojure.lang.RestFn.applyTo(RestFn.java:137)
    at clojure.core$apply.invoke(core.clj:632)
    at clojure.core$require.doInvoke(core.clj:5832)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at user$eval5$fn__7.invoke(form-init2532813080817058510.clj:1)
    at user$eval5.invoke(form-init2532813080817058510.clj:1)
    at clojure.lang.Compiler.eval(Compiler.java:6782)
    at clojure.lang.Compiler.eval(Compiler.java:6772)
    at clojure.lang.Compiler.load(Compiler.java:7227)
    at clojure.lang.Compiler.loadFile(Compiler.java:7165)
    at clojure.main$load_script.invoke(main.clj:275)
    at clojure.main$init_opt.invoke(main.clj:280)
    at clojure.main$initialize.invoke(main.clj:308)
    at clojure.main$null_opt.invoke(main.clj:343)
    at clojure.main$main.doInvoke(main.clj:421)
    at clojure.lang.RestFn.invoke(RestFn.java:421)
    at clojure.lang.Var.invoke(Var.java:383)
    at clojure.lang.AFn.applyToHelper(AFn.java:156)
    at clojure.lang.Var.applyTo(Var.java:700)
    at clojure.main.main(main.java:37)
Caused by: clojure.lang.ArityException: Wrong number of args (2) passed to: StringReader
    at clojure.lang.AFn.throwArity(AFn.java:429)
    at clojure.lang.AFn.invoke(AFn.java:36)
    at instaparse.cfg$eval10231$safe_read_string__10232.invoke(cfg.clj:163)
    at instaparse.cfg$process_string.invoke(cfg.clj:180)
    at instaparse.cfg$build_rule.invoke(cfg.clj:217)
    at clojure.core$map$fn__4553.invoke(core.clj:2622)
    at clojure.lang.LazySeq.sval(LazySeq.java:40)
    at clojure.lang.LazySeq.seq(LazySeq.java:49)
    at clojure.lang.RT.seq(RT.java:507)
    at clojure.core$seq__4128.invoke(core.clj:137)
    at clojure.core$apply.invoke(core.clj:630)
    at instaparse.cfg$build_rule.invoke(cfg.clj:215)
    at clojure.core$map$fn__4553.invoke(core.clj:2622)
    at clojure.lang.LazySeq.sval(LazySeq.java:40)
    at clojure.lang.LazySeq.seq(LazySeq.java:49)
    at clojure.lang.RT.seq(RT.java:507)
    at clojure.core$seq__4128.invoke(core.clj:137)
    at clojure.core$apply.invoke(core.clj:630)
    at instaparse.cfg$build_rule.invoke(cfg.clj:211)
    at instaparse.cfg$build_rule.invoke(cfg.clj:214)
    at clojure.core$map$fn__4553.invoke(core.clj:2622)
    at clojure.lang.LazySeq.sval(LazySeq.java:40)
    at clojure.lang.LazySeq.seq(LazySeq.java:49)
    at clojure.lang.RT.seq(RT.java:507)
    at clojure.core$seq__4128.invoke(core.clj:137)
    at clojure.core$apply.invoke(core.clj:630)
    at instaparse.cfg$build_rule.invoke(cfg.clj:215)
    at clojure.core$map$fn__4553.invoke(core.clj:2622)
    at clojure.lang.LazySeq.sval(LazySeq.java:40)
    at clojure.lang.LazySeq.seq(LazySeq.java:49)
    at clojure.lang.RT.seq(RT.java:507)
    at clojure.core$seq__4128.invoke(core.clj:137)
    at clojure.core$apply.invoke(core.clj:630)
    at instaparse.cfg$build_rule.invoke(cfg.clj:211)
    at instaparse.cfg$build_rule.invoke(cfg.clj:207)
    at clojure.core$map$fn__4553.invoke(core.clj:2622)
    at clojure.lang.LazySeq.sval(LazySeq.java:40)
    at clojure.lang.LazySeq.seq(LazySeq.java:49)
    at clojure.lang.RT.seq(RT.java:507)
    at clojure.core$seq__4128.invoke(core.clj:137)
    at clojure.core.protocols$seq_reduce.invoke(protocols.clj:30)
    at clojure.core.protocols$fn__6506.invoke(protocols.clj:101)
    at clojure.core.protocols$fn__6452$G__6447__6465.invoke(protocols.clj:13)
    at clojure.core$reduce.invoke(core.clj:6519)
    at clojure.core$into.invoke(core.clj:6600)
    at instaparse.cfg$ebnf.invoke(cfg.clj:277)
    at clojure.lang.AFn.applyToHelper(AFn.java:154)
    at clojure.lang.AFn.applyTo(AFn.java:144)
    at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:3623)
    ... 125 more

所以花了一些时间才意识到我的 clojure 版本有误。 因为这个错误从我得到的堆栈跟踪中绝对不清楚。

有谁能帮我解释一下这个堆栈跟踪到底说明了什么?我应该如何理解 clojure 版本不好?顺便说一句,为什么它不是好版本?

那个堆栈跟踪很不幸。它对理解正在发生的事情没有多大帮助。在不深入挖掘的情况下,我们最多可以说 "something is wrong while compiling instaparse"。你不必知道什么是 instaparse,但它被 compojure 使用。

问题是:clojure 版本没有错。只是compojure 1.3.1 与clojure 1.7.0 不兼容。 Clojure 1.7.0 是最后一个稳定版本。您可以使用 1.6.0 或 1.7.0。只是如果你打算使用 clojure 1.7.0,那么 compojure 版本是错误的(当然你不必知道)。尝试在 clojure 1.7.0 上使用 [compojure "1.3.4"],一切都应该没问题。

来自 Clojure Stack Traces for the Uninitiated 我将在面对 clojure 堆栈跟踪时采取一些指导:

  1. 查找最终原因:查找以"Caused by"开头的最后一行。这就是异常的来源。
  2. 寻找你的命名空间(如果有的话,我会补充说,寻找不同于"clojure"的命名空间):在这种情况下,它会我们说 "oh, something is wrong with instaparse!".
  3. 打开你的解码器环(或找到$符号):这里我们对clojure如何编译我们的代码有了一些了解。需要知道的一件重要事情是,每个函数都被编译成一个单独的 class,而且很多时候我们可以通过 $ 符号后面的内容来识别该函数。在这种情况下,从 instaparse.cfg$process_string.invoke(cfg.clj:180) 我们可以假设问题出在 instaparse 中 cfg.clj 的第 180 行,其中定义了 process_string* 函数。

* 很可能是 process-string 因为改名了,但那是另一回事了。