Clojure&ClojureScript:clojure.core/read-string,clojure.edn/read-string和cljs.reader/read-string

 Tow-face信信 发布于 2023-01-04 12:21

我不清楚所有这些读字符串函数之间的关系.好吧,很明显clojure.core/read-string可以读取由pr[n]或甚至输出的任何序列化字符串print-dup.很明显,clojure.edn/read-string读取根据EDN规范格式化的字符串.

但是,我从Clojure脚本开始,并不清楚是否cljs.reader/read-string遵守.这个问题是由于我有一个Web服务正在发出以这种方式序列化的clojure代码:

(with-out-str (binding [*print-dup* true] (prn tags)))

那就是产生包含数据类型的对象序列化.但是,这是不可读的cljs.reader/read-string.我总是得到这种类型的错误:

Could not find tag parser for = in ("inst" "uuid" "queue" "js")  Format should have been EDN (default)

起初,我认为这个错误被抛出cljs-ajax但是在测试了cljs.reader/read-string一个rhino REPL后,我得到了同样的错误,这意味着它cljs.reader/read-string本身就被抛出了.它是由maybe-read-tagged-type函数引发的,cljs.reader但不清楚这是因为读者只能使用EDN数据,还是......?

另外,根据与Clojure文档的差异,唯一可以说的是:

The read and read-string functions are located in the cljs.reader namespace

这表明他们应该完全具有相同的行为.

1 个回答
  • 简介:Clojure是EDN的超集.默认情况下,pr,prnpr-str,给Clojure的数据结构时,产生有效的EDN.*print-dup*改变这一点并使它们使用Clojure的全部功能,以便在往返后更好地保证内存中对象的"相同性".ClojureScript只能读取EDN,而不是完整的Clojure.

    简单的解决方案:不要设置*print-dup*为true,只将纯数据从Clojure传递给ClojureScript.

    更难的解决方案:使用带标记的文字,两边都有(可能是共享的)相关阅读器.(但这仍然不会涉及*print-dup*.)

    切向相关:大多数用于EDN的用例由Transit覆盖,这更快,特别是在ClojureScript方面.


    让我们从Clojure部分开始.Clojure从一开始就有一个clojure.core/read-string函数,它read是Read-Eval-Print-Loop的旧Lispy意义上的字符串,即它允许访问Clojure编译中使用的实际读者.[0]

    后来,Rich Hickey&co决定推广Clojure的数据符号,并发布了EDN规范.EDN是Clojure的一个子集 ; 它仅限于Clojure语言的数据元素.

    由于Clojure是一个Lisp,并且像所有lisps一样,吹嘘"代码是数据是代码"的哲学,上段的实际含义可能并不完全清楚.我不确定在任何地方都有详细的差异,但仔细检查Clojure Reader描述和前面提到的EDN规范会显示一些差异.最明显的区别在于宏字符,特别是#调度符号,它在Clojure中比在EDN中有更多目标.例如,#(* % %)符号是有效的Clojure,Clojure读者将变成以下EDN的等价物:(fn [x] (* x x)).对于这个问题特别重要的是几乎没有记录的#=特殊读取器宏,它可以用于在读者内部执行任意代码.

    由于Clojure阅读器可以使用完整的语言,因此可以将代码嵌入到阅读器正在阅读的字符串中,然后在阅读器中对其进行评估.可以在这里找到一些例子.

    clojure.edn/read-string功能严格限于EDN格式,而不是整个Clojure语言.特别是,它的操作不受*read-eval*变量的影响,并且它无法读取所有可能的有效Clojure代码片段.

    事实证明,由于历史原因,Clojure读者用Java编写.由于它是一个重要的软件,运行良好,并且经过大量的调试和经过多年积极的Clojure在野外使用的战斗测试,Rich Hickey决定在ClojureScript编译器中重用它(这是主要的原因) ClojureScript编译器在JVM上运行.ClojureScript编译过程主要发生在JVM上,其中Clojure读取器可用,因此ClojureScript代码由clojure.core/read-string(或更确切地说是它的近亲clojure.core/read)函数解析.

    但是您的Web应用程序无法访问正在运行的JVM.要求ClojureScript应用程序的Java applet看起来并不是一个非常有前途的想法,特别是因为ClojureScript的主要目标是将Clojure语言的范围扩展到JVM(和CLR)的范围之外.因此决定ClojureScript无法访问自己的读者,因此也无法访问自己的编译器(即ClojureScript中没有evalread没有read-string).这个决定及其影响将在这里更详细地讨论,实际上知道事情是如何发生的(我不在那里,所以在这个解释的历史视角中可能存在一些不准确之处).

    所以ClojureScript没有相应的clojure.core/read-string(有些人认为它不是真正的口齿不清).仍然,有一些方法可以在Clojure服务器和ClojureScript客户端之间传递Clojure数据结构,这确实是EDN工作中的激励因素之一.正如Clojure 在EDN规范发布后获得了限制(和更安全)的阅读功能(clojure.edn/read-string),ClojureScript也在标准发行版中获得了EDN阅读器cljs.reader/read-string.可能有人认为,这两个函数的名称(或者更确切地说是它们的名称空间)之间的一致性会更好.

    在我们最终回答你原来的问题之前,我们还需要一些关于这个问题的背景知识*print-dup*.请记住,这*print-dup*是Clojure 1.0的一部分,这意味着它早于EDN,标记文字的概念和记录.我认为EDN和标记文字为大多数用例提供了更好的选择*print-dup*.由于Clojure通常建立在一些数据抽象(列表,向量,集合,映射和通常的标量)之上,因此打印/读取周期的默认行为是保留数据的抽象形状(地图是地图),但不是特别是它的具体类型.例如,Clojure的具有地图多个抽象实现方式中,如PersistentArrayMap用于小型地图和PersistentHashMap更大的一个.该语言的默认行为假定您不关心具体类型.

    对于您所做的极少数情况,或者对于更专业的类型(当时使用deftype或defstruct定义),您可能希望更多地控制如何读取这些类型,这就是print-dup的用途.

    关键是,*print-dup*设置为true,pr并且系列不会产生有效的EDN,但实际上Clojure数据包括一些显式#=(eval build-my-special-type)形式,这些形式都不是有效的EDN.

    [0]:在"lisps"中,编译器是根据数据结构明确定义的,而不是根据字符串定义的.虽然这看起来与通常的编译器(在处理过程中确实将字符流转换为数据结构)有些不同,但Lisp的定义特征是读者发出的数据结构是常用的数据结构.语言.换句话说,编译器基本上只是该语言中始终可用的函数.这不像过去那样独特,因为大多数动态语言都支持某种形式eval; Lisp的独特之处在于它eval采用数据结构,而不是字符串,这使得动态代码生成和评估变得更加容易.编译器"只是另一个函数"的一个重要含义是编译器实际上运行时已经定义并可用的整个语言,并且到目前为止读取的所有代码也可用,这为Lisp宏系统打开了大门.

    2023-01-04 12:22 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有