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

欢迎!请查看关于页面以获取更多关于如何使用本站的信息。

+1
语法和读取器

edn/read:readers 参数接收一个将标签符号映射到数据读取函数的映射,但 *data-readers* 需要 一个将标签符号映射到数据读取 Vars (全局绑定)的映射。我只想知道是否有任何理由造成这种差异,因为无法在 *data-readers* 中使用匿名函数真是太遗憾了。

背景是,我制作了一些相关的读取器标签(用于标记文字),它们都工作得很好,所以我不想创建 5 个几乎相同的读取器函数,因此我只创建了一个一个参数的函数(标记,值),然后我制作了一个 reader-for 函数,该函数根据需要返回一个一参数函数(使用 partial 和两个参数的函数)。这对于 edn/read 来说工作得很好,但是当我尝试在 *data-readers* 中使用它时,因为 reader-for 的输出没有 Var,所以行不通。

有几个解决方案。例如,绑定 *default-data-reader-fn*并制作一个函数来转发到所有我的读取器。这并不特别困难,但我现在有两个工件而不是一个 - 一个为 edn/read 的读取器映射和一个用于 *default-data-reader-fn* 的函数。当然可以在函数中利用这个映射。或者,作为一种替代方案,我可以直接编写五个函数——“编写”五个省份函数。但这些保留标记处理上的不一致性有点让人费解。(例如,除了 {tag-sym fn}:reader 映射和 {tag-sym Var}*data-readers* 映射外,还有 data_readers.clj 中的 {unquoted-tag-sym-in-a-map-literal fn-sym} 语法,尽管它是一个 clj 文件,但它似乎不提供任何机会来进行动态定义读取器,只是提供字面量映射)。

可能是我还没有掌握所有这些实用、历史和逻辑,如果有人能提供一些启发,那将不胜感激,如果没有也行。

1 答案

+2

选中
 
最佳答案

我在开发这个功能时不在核心团队,所以我只能猜测,但我猜想 *data-readers* 有意与 data_readers.clj 的结构相关。

对于 data_readers.clj,其目的是允许你在必须加载的代码中连接一个标签到读取函数。该文件是 .clj 而不是 .edn,因为数据读取器是在 Clojure 1.4 中添加的,而 edn 规范还没有编写(那是在同年稍后发布的)。

许多 Clojurists 可能遇到的一个长期问题是在 edn 中没有标准方式来表示对可调用代码引用的引用,如 var。你最多只能发送符号,并在需要时解析它们以恢复 Var。在过去的几个版本中,我们逐步实现了对这个问题的解决方案 - Var 序列化(在 Java 中)现在在反序列化时会重新连接到本地实现,添加了 require-resolve,并有助于符号方面。下一步可能的步骤是将 vars 序列化到 edn(#var my/fn),然后创建一个内置的数据读取器以反序列化到已解析的 Var。如果我们有这样的话,可能就是 data_readers.edn,其中 vals 都是标记为 var 的文本,而不是符号。

我觉得我的真正问题是你是否可以再深入一层 - 为什么你要篡改 *data-readers*?你为什么不能直接注入你想要的数据读取器映射?

感谢,亚历克斯,我非常感激你对历史的详细解释,这让一切都有了意义。为了回答你关于我为什么要对 *data-readers* 进行修改的问题,我认为当时的我并没有理解 data_readers.clj 已经能满足我的所有需求。例如,我当时并不清楚这个文件可以与库一起分发并正常工作(我以为这只是个别用户创建的东西)。我也没意识到它在 REPL 中的工作情况很好,可能是因为我花了点时间才正确地使用语法,与此同时,它并没有在 REPL 中加载。(我误将我的标签重命名为命名空间,例如 "foo.bar.baz",而不是像符号一样,"foo.bar/baz",虽然我不记得这到底是 data_readers.clj 的问题还是 *data-readers* 的问题。但它与 edn/read 一起使用这种方式命名标签时工作正常,所以我花了点时间才意识到我哪里做错了。)

不管怎样,最终我发现我并不需要修改 *data-readers*。再次感谢你的深思熟虑的回答。
...