2024 年 Clojure 周报 中分享您的想法!

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

+1
打印

对于函数的 print-method 实现,是为了产生有效的 edn 语法吗?在有些情况下,它并没有做到。

user> (require '[org.httpkit.server :as http])
user> (def s (http/run-server (fn [req] {:status 200}) {}))
user> (prn s)
#function[clojure.lang.AFunction/1]

符号名称不能以数字开头,因此 clojure.lang.AFunction/1 在读取时会引发解析错误

user> (clojure.edn/read-string (prn-str s))
Execution error at user/eval7394 (REPL:68).
Invalid token: clojure.lang.AFunction/1

这是预期的行为吗?如果是这样,打印和重新读取可能包含函数的数据结构可能会失败。

1 答案

0

被选中
 
最佳答案

是的,这是预期的行为。以这种方式序列化函数是不可能的,edn 也没有函数实例的表示。

我猜创建不可读标签字面量的数字可能被认为是一个问题。
谢谢,Alex。我好奇的就是那个不可读的标签字面量。处理标签字面量是另一个话题;但我认为print-method应该生成语法有效的edn。
一般情况下,print-method并不能保证生成语法有效的edn(有许多方法会违反这个假设),甚至不能保证打印Clojure数据。是否支持edn打印或在1.11版本中更强大地支持print/read循环是一个正在考虑中的工作项。
在1.11版本中看到这一点将非常棒。如果这有助于思考这项工作的细节,这里是我在发布原始问题时未注意到的细节:

不可读的标签字面量似乎不是由Clojure本身生成的。cider-nrepl为某些对象类型添加了print-method实现,包括clojure.lang.AFunction。这通常是很有帮助的;但多方法的全局性质意味着这可能会出错(或至少会让你困惑)。我惊讶地看到在vanilla repl中测试时pr-str产生了不同的结果。一种始终一致(不受环境影响)且保证可读(由edn读者读取)的打印数据结构的方式确实是一个很有用的特性。
by
哦,对了,我没有意识到这其实是cider增加的打印函数。

整个打印基础设施旨在允许用户修改,所以我认为让它独立于环境并不是目标。
by
当然——允许用户修改是关键,但明确的范围有助于最小化惊讶原则。

例如,edn/read的opts参数使得用户定义的行为清晰且易于推理。相比之下,在使用print-method的情况下,我没有修改默认行为,但其他东西却做到了——全局的。它有一个好理由。但这让人惊讶,而且寻找原因并不简单。
...