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

欢迎!请查看 关于 页面了解有关此信息的一些更多信息。

+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* 的函数。当然,可以在该函数中使用该映射。或者作为替代,我可以直接编写五个函数 -- 或者使用 doseq 来“编写”。但是,关于如何执行这些标记的小不一致性是有点令人困惑。(例如,除了 :reader{tag-sym fn} 映射和 {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以帮助解决符号方面的问题。下一步可能是将var序列化为edn(#var my/fn),然后创建一个内置的数据读取器以反序列化为解析后的Var。如果我们有了所有这些,可能就是data_readers.edn,其值为带有var标记的文字,而不是符号。

我的真正问题是你是否可以再深入一层 - 你为什么需要玩弄*data-readers*的上下文是什么?在哪种上下文中你无法直接将所需的数据读取器映射注入到读取器中?

多谢,Alex,我非常感谢你对历史的详尽解释,这让我对事物有了更深的理解。为了回答你关于我为什么摸着 *data-readers* 的疑问,我觉得我当时不太明白 data_readers.clj 包含了我需要做的一切。例如,我当时并不清楚这个文件可以与库一起分发并且可以正常工作(我以为这只是个别用户制作的东西)。我也没有意识到它在 REPL 中也能正常工作,可能是因为我花费了一段时间才正确地处理好语法,同时在那个过程中它并没有在 REPL 中加载。(我错误地将命名空间“foo.bar.baz”当作标签,而不是像符号“foo.bar/baz”,尽管我记不太清这是不是 data_readers.clj 的问题或者只是 *data-readers* 的问题。它可以与 edn/read 一起以这种方式命名标签,所以我花了点时间才意识到我哪里做错了。)

无论如何,我发现我并不需要摸着 *data-readers*。再次感谢你深思熟虑的回答。
...