请分享您的想法,参加2024年clojure现状调查!

欢迎!请参阅关于页面了解这个工作的更多详情。

+2
错误

Clojure的堆栈跟踪比较晦涩,难以理解,是否有库可以以更好的方式显示错误或格式化堆栈跟踪?

2 个回答

+1

有一些库可以对堆栈跟踪的打印进行修改,提供诸如折叠、Clojure框架和颜色化等内容。我们目前在下一个Clojure版本中没有计划进行这方面的技术开发。

您能否指给我哪些是这些库?
Michel,如果你还没有升级到Clojure 1.10.1,我建议你升级。在1.10中,错误信息做了大量工作,在1.10.1中增加了更好的报告机制。

我还会发个链接到Stuart Halloway关于堆栈跟踪的Twitter话题:https://twitter.com/stuarthalloway/status/1148295437448876032

当你刚开始使用Clojure时,堆栈跟踪可能会让你感到害怕,但学习如何阅读它们是值得努力的,坦白说,折叠/省略它们并不像你想的那么有帮助(因为有时重要的信息被这些库隐藏了)。
当我听说更好的错误信息时,这是我对于1.10中将要发生的事情的看法
https://reasonml.github.io/blog/2017/08/25/way-nicer-error-messages.html

像'''ClassCastException java.lang.Long cannot be cast to clojure.lang.IFn'''这样的错误对新手来说可能是神秘的,请参阅:https://stackoverflow.com/questions/26720847/classcastexception-java-lang-long-cannot-be-cast-to-clojure-lang-ifn

对我来说,这里的价值增加是可以指向用户源代码中错误的列和行,以快速显示错误在嵌套事物中的位置

并且要改进Clojure术语中解释错误发生原因的方式,而不是用Java的方式,我真的不想知道类,因为在我看来,我的代码中没有类,即(1 2 3)

尽管如此,我确实对此不屑一顾,我们在这个语言中有大量的交互,这可能使这比在像elm这样的封闭系统中更困难。
by
Clojure_可以_检测这些条件并抛出更详细的异常,但这会给所有人带来性能负担。从历史传统来看,一直追求速度,忍受“异常”的Java异常,因为每个新来者只需学习这些“一次”-- 所以这对绝大多数用户来说是一个很好的权衡。

话虽如此,如果有一个内置的“友好”REPL选项,它会使用:caught来提供更友好的错误信息,那就更好了。
by
以一个例子为例

user=> (defn easy [t]
                (clojure.main/repl-caught
                    (if (re-find #"cannot be cast to clojure.lang.IFn" (ex-message t))
                        (ex-info (str "Expected a function -- found: " (second (re-find #"^([^ ]*)" (ex-message t)))) {:cause t})
                    t)))
#'user/easy
user=> (clojure.main/repl :caught easy)
user=> (1 2 3)
执行错误(ExceptionInfo)在用户/easy(REPL:1)。
期望一个函数--找到: java.lang.Long
user=>
+1
by

这是对拥有更好的开箱即用错误信息的另一个支持。

以下提到的库在处理症状方面或多或少成功地处理了这些问题,但让我们从一个想要学习Clojure的人的角度来看,因此他们访问Clojure.org,点击“入门”。

好了,现在我知道如何下载它。也许我会尝试通过使用 repl.it 来感受它。
现在我有了一个基本的经验(带有clojure.org中令人困惑的错误消息)(见:“你可能会意外尝试将数据列表作为代码评估,产生的令人困惑的错误”)

总之,让我们先学习Clojure。
好了,关于如何启动REPL,还是一无所知。
第三个链接:启动REPL是一个好主意。
第四个链接:这里有 n 种启动 REPL 的方法。
这里还有其他运行 REPL 的方法。

没有一个提到:如果你是初学者,让我们添加 clj-stacktrace,然后启动一个 REPL。
你看到这是不切实际的原因了吗?

我知道你近年来在编写更好的文档方面付出了很多努力,我不忍指出这些事情。很难回到如此熟悉的事物,并以想要学习这门新语言的开发者的眼光来看它。

我相信你有一次或可能两次机会给人留下好印象,并且能够让用户读得懂的错误信息告诉我们哪里出错,这是其中一个重要部分。

user=> (map 1 inc)
不知道如何从 clojure.core$inc 创建 ISeq

user=> (1 2 3)
执行错误(ClassCastException)在 user/eval7(REPL:1)。class java.lang.Long 不能转换为 class clojure.lang.IFn(java.lang.Long 在 java.base 模块中;clojure.lang.IFn 在未命名的模块中)

这两者都没有告诉我我哪里做错了。它们只是告诉我一些关于 Lisp 解释器在幕后如何工作的细节。(其中一些已经记录在 clojure.org 上)。

由于这些对我不太有帮助,我是新用户,我将去谷歌搜索。
对于初学者来说,谷歌搜索错误信息(如参数顺序错误或尝试调用无法调用的方法)的容忍度并不高。

这就是你留下错误信息指引用户不重要的印象的地方。
(顺便说一句,奇怪的是,你处理 (nil 2 3) 比较好,并没有抛出 NPE)

这就是 Clojure(实现)积极参与到“巨大的学习曲线”这一说法的原因。
虽然我经常看到这个错误,但我已经学会了它的意思。(关于 Sean 的评论)

损害已经造成了。

其他 Clojure 方言在这里做得更好。(例如 CLJS 和 Sci)。

说到努力:有一种反对意见认为提供更好的错误信息会影响性能。如果我们在这里谈论异常处理(以及上述两种情况都是如此),
我不清楚性能影响在哪里。
由于 s-expr 失败而进行的异常处理不应该是在性能关键路径上的,我想。
我很高兴更好地理解性能方面如何发挥作用。

仅就上述两个示例错误信息而言,从用户的视角而不是系统的视角编写它们的努力并不大。对于其中的一个来说,意味着更改 RT.java 中的第 557 行。

更好的错误信息可能意味着捕获更底层的异常,将它们与当前的 AST 关联,并以与产生错误的消息元素相关的消息重新抛出。

我恳请你们引导初学者获得最好的 REPL。
让这个默认的入门步骤和学习 Clojure。
然后你可以说:你知道,下面是 IFn 和 ISeq,你可能看到 Java 堆栈跟踪。

在 Clojure 路径上,有许多新概念需要学习和理解。重新解释错误信息不应该是其中之一。

by
还有另一个Clojure初学者遇到了ClassCastException问题。

https://www.reddit.com/r/Clojure/comments/gzudzn/problem_defining_fibonacci_function/
by
"好吧,关于如何启动REPL还没有任何消息。" —— 在看到你最近对这个答案的评论后,我意识到安装说明没有提到安装后该做什么,所以我向起点页面提交了一个PR,添加了在安装后运行clj或clojure以启动REPL的说明。Alex将其合并,所以我希望这是个改进,尽管很微小。
by
谢谢,Sean。
重新阅读文档,从对现在来说第二本能的概念不熟悉的初学者的角度来看,并非易事。

沿着这个思路,也许最好在页面上直接收集对文档的反馈。许多公司尝试改善面向非专家的文档时都会这么做。也许有一个反馈按钮,能比这个更好一些:https://docs-feedback.aws.amazon.com/feedback.jsp?feedback_destination_id=068c0217-1615-4028-b3f7-7de2fb227b77&topic_url=https://aws.amazon.com/getting-started/hands-on/build-web-app-s3-lambda-api-gateway-dynamodb/module-one/
(仅为例)
...