2024 年 Clojure 状态调查!分享你的想法。

欢迎!请查阅关于页面以了解更多关于它的工作方式的信息。

+1 支持
语法和读取器

如果数据读取器返回 nil,则读取器会抛出 java.lang.RuntimeException: 没有分发宏... 错误消息表明,第一个字符的标签对应没有分发宏。

这里有一个简单的示例

`
user=> (binding [*data-readers* {'f/ignore (constantly nil)}]

     (read-string "#f/ignore 42 10"))

RuntimeException 没有分发宏:f clojure.lang(Util.runtimeException (Util.java:219))
`

原始读取器代码没有区分数据读取器不存在和适当数据读取器返回的 nil 值。因此它感到困惑,并试图寻找分发宏,将其送入错误代码路径的更低层,最终产生误导性的错误消息。

原始文档没有将 nil 识别为非法值。很明显,这个错误是原始数据读取器代码中的疏忽,而不是一个有意设计的特性。

补丁使用哨兵值来区分丢失数据读取器的情况和返回 nil 值的情况。

补丁: clj-1139-2.patch

15 答案

0 支持

评论者:[email protected]

clj-1138-allow-data-reader-to-return-nil-instead-of-throwing.patch 允许数据读取器返回 nil 而不是抛出异常。对可能的标签或记录进行健全性检查,为可能是分发宏的特殊字符提供更好的错误反馈(而不是假设它是一个已标记的字面量)。

0 支持

评论者:[email protected]

clj-1138-data-reader-return-nil-for-no-op.patch 允许数据读取器返回 nil,并由读取器视为无操作(类似 #_)。通常,nil 不是一个有用的值(实际上它会在 Clojure 1.4 到 1.5 RC2 版本中引发异常)。使用这个补丁,可以使用数据读取器实现类似条件功能的读取器。

0 支持

评论者:[email protected]

clj-1138-allow-data-reader-to-return-nil-instead-of-throwing.patch 是第一个需要考虑的补丁。它仅允许数据读取器返回 nil 作为值,并以 nil 作为最终值返回。我认为它实现了最初为分派宏设计的意图,并在许多情况下提供了更好的错误消息(大多数是拼写错误)。

第二个补丁 clj-1138-data-reader-return-nil-for-no-op.patch 依赖于首先应用其它补丁。它采取额外的一步,将数据读取器返回的 nil 值视为对读取器的无操作(类似 #_)。

0 支持

评论者:[email protected]

实际上,你可以通过让你的数据读取器返回 '(quote nil)' 而不是普通的 nil 来解决这个问题。这个表达式会评估为 nil,因此你可以在需要时获取 nil。使用补丁之后也是如此,如果你真的想返回 nil,仍然有方法可以做到这一点。

(binding (link: *data-readers* {'x/nil (constantly '(quote nil))}) (read-string "#x/nil 42"))
;=> (quote nil)
0 支持

评论者:jafingerhut

如果使用以下命令,则补丁 clj-1138-allow-data-reader-to-return-nil-instead-of-throwing.patch 日期为 2012 年 12 月 22 日,且可干净地应用到最新的 master 版本

% git am --keep-cr -s --ignore-whitespace < clj-1138-allow-data-reader-to-return-nil-instead-of-throwing.patch

如果没有 --ignore-whitespace 选项,补丁会失败,仅仅因为 Clojure master 最近改变了某些空白字符。

0 支持

评论者:jafingerhut

好的,现在最新的 master 版本(当时是 1.5.0-RC15),补丁 clj-1138-allow-data-reader-to-return-nil-instead-of-throwing.patch 无法干净地应用到 master 上,甚至使用上面的 'git am' 命令并添加 --ignore-whitespace 选项也不行。Steve,如果你能查看需要更新的内容,那将是极好的。像 "Updating stale patches" 部分中建议的那样使用 patch 命令还不够,因此可能需要手动仔细检查哪些内容需要更新。

0 支持

评论者:[email protected]

我去掉了我的补丁。近期 LispReader 和新的 EdnReader 发生了一些变化。

0 支持

评论者:alexmiller

修复了空格警告并更新了补丁,使其生效,无语义更改,保留在 clj-1139-2.patch 中。

0 支持

评论者:alexmiller

此工单需要对问题和采取的补丁方法提供更好的描述。

0 支持

评论者:[email protected]

如果问题不明确,我会问为什么数据读取器返回 nil 会特殊处理?如果它是设计上的非法操作,这个错误信息是否会告知用户?

在提交 bugs 的时候我没有找到任何文档化的限制,今天也没有找到。所以对我来说这看起来只是一个简单的 bug。数据读取器应该允许返回 nil,Clojure 读取器应该按常规处理 nil。我的解决方案是返回 (quote nil),这样可以在不引发 bug 的情况下得到预期的行为。

0 支持

评论者:alexmiller

欢迎对描述进行更多更新。我的问题是是否调用数据读取器函数应该返回 nil。有什么正当的理由需要这么做?使用读取器读取非 nil 标记值的描述似乎会导致返回 nil,这是令人困惑的。这不可能进行往返并因此看起来是不对称的。

0 支持
注释者:[email protected]

“法无禁止即自由”,或者说,除非你说它是非法的,否则我应该能够这样做。我的简单例子是 {{#C NULL}},对我来说它很明显就是空值。

回顾这个问题,我看出来大多数人认为标记字面量是将外值编码在Clojure字面量中的方式。如果你只关注可扩展数据表示法,谁还需要另一种写入nil的方式呢?这是一个公正的问题。

我想使用数据读取器作为某种受限的读取宏(如Common Lisp中所用)。我在做一些平台特定的操作时发现了这个错误(在读取条件实现之前很久)。在我的情况下,在“其他”平台上返回nil很方便。

许多数据读取器的使用并非双射。例如,{{#infix (3 + 4)}} 解释为常量7,也没有进行往返处理。除非你是Dan Friedman或Wil Byrd,往返是一项艰巨的要求。:-)

我会尽量提供更多上下文的描述,但我不想让我的非常规使用分散了人们对明显的错误(和错误的消息)的注意力。
0 支持

评论者:[email protected]

顺便说一下,这个错误是CLJ-1138,但提议的补丁说“1139”,这可能会让一些忙碌的审阅者感到困惑。

0 支持
注释者:[email protected]

我已经测试了这个补丁,并且它在当前的master分支上工作得很好。我建议添加另一个测试来确认edn/read-string也能正确工作。以下是我的测试代码。这也测试了覆盖默认读取器是否工作。如果您想使用此测试请随意。


(deftest clj-1138-uuid-override
  (is (nil? (binding [*data-readers* {'uuid (constantly nil)}]
              (read-string "#uuid \"550e8400-e29b-41d4-a716-446655440000\""))))
  (is (nil? (edn/read-string {:readers {'uuid (constantly nil)}}
                                    "#uuid \"550e8400-e29b-41d4-a716-446655440000\""))))

0 支持
...