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

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

+1
语法和读取器

如果数据读取器返回nil,则读取器会抛出java.lang.RuntimeException: No dispatch macro... 错误消息暗示对于标签的第一个字符没有相应的分配宏。

这里有一个简单的例子

`
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而不是引发异常。对可能的标签或记录执行sanity check,以确保它是Java标识符的起始字符。对于可能是分配宏的特殊字符提供了更好的错误消息(而不是假设它是 tagged literal)。

0

[email protected]发表的评论

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

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

date 为 2012 年 12 月 22 日的补丁 clj-1138-allow-data-reader-to-return-nil-instead-of-throwing.patch,如果你使用以下命令,仍然可以干净地应用到最新的 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 已经不能再干净地应用,即使在上面给出的 'git am' 命令中使用 --ignore-whitespace 选项。Steve,如果你能查看需要更新的内容,那就太好了。使用“更新过时的补丁”部分中提到的 "Updating stale patches" 部分的建议,还不够,所以可能需要手动仔细检查以确定哪些需要更新。

0

[email protected]发表的评论

我移除了我的补丁。近期LispReader和新的EdnReader有了一些变化。

0

评论者:alexmiller

修复了空白符警告,并更新了补丁以使其可以应用,没有语义变化,在clj-1139-2.patch中保留了归属。

0

评论者:alexmiller

问题需要更好的问题描述和补丁中采用的方法。

0

[email protected]发表的评论

如果问题不太清楚,我会问为什么对于一个数据读取器,nil 返回值会得到特殊处理?如果它按照设计被视为非法,这个错误信息是否能让用户有所启发?

在提交错误时,我没有找到任何已记录的限制,今天也没有找到任何限制。所以对我来说这是一个简单的错误。数据读取器应该允许返回nil,Clojure读取器应该像往常一样处理nil。我的解决方案是返回(quote nil),这给出了预期的行为而没有触发错误。

0

评论者:alexmiller

希望能有更多关于描述的更新。我的问题可能是:调用数据读取器函数时,是否应该永远返回nil?是否有好的用例需要这样做?看起来您正在用读取器读取一个非nil标记值的描述,因此返回nil会比较令人困惑。这不可能进行双向转换,因此似乎是不同的。

0
评论由:[email protected] 制作_

_Nulla poena sine lege_ 或者基本上,除非你说它是非法的,我应该能够做到。我的简单例子是 {{#C NULL}},这在我看来看起来显然是 nil。

回顾这个问题,我发现大多数人认为标签化字面量是将外部值编码在 Clojure 字面量中的方式。如果你只关心可扩展的数据表示法,谁还需要另一种写 nil 的方法?这是一个合理的问题。

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

数据读取器的许多用途不是一一对应的。例如,{{#infix (3 + 4)}} interpreting constant 7 as also not round-trippable. 除非你是 Dan Friedman 或 Wil Byrd,重考是一个艰难的要求。:-)

我将尝试用更多的上下文更新我的描述,但我不想让任何人因为我的非正统用法而分心,从而忽视了显然的 bug(以及错误的消息)。
0
by

[email protected]发表的评论

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

0
by
评论由:[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
by
...