gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-03 01:29:20 28 4
gpt4 key购买 nike

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

不过我是从Clojure Script开始的,不清楚cljs.reader/read-string遵守。这个问题是由于我有一个以这种方式序列化 clojure 代码的 Web 服务引发的:

(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在犀牛 REPL 中,我得到了同样的错误,这意味着它是由 cljs.reader/read-string 抛出的本身。它是由 maybe-read-tagged-type 抛出的函数在 cljs.reader但尚不清楚这是因为阅读器仅使用 EDN 数据,还是...?

另外,来自 Differences from Clojure文件,唯一说的是:
The read and read-string functions are located in the cljs.reader namespace

这表明它们应该具有完全相同的行为。

最佳答案

简介: Clojure 是 EDN 的超集。默认情况下,pr , prnpr-str , 当给定 Clojure 数据结构时,生成有效的 EDN。 *print-dup*改变了这一点,使它们能够充分利用 Clojure 的强大功能,在往返后对内存中的对象的“相同性”提供更有力的保证。 ClojureScript 只能读取 EDN,不能读取完整的 Clojure。

简单的解决办法:不设置*print-dup*为 true,并且只将纯数据从 Clojure 传递到 ClojureScript。

更难的解决方案:使用标记文字,双方都有(可能是共享的)关联阅读器。 (不过,这仍然不会涉及 *print-dup* 。)

切线相关:Transit 涵盖了 EDN 的大多数用例,这更快,尤其是在 ClojureScript 方面。

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

后来,Rich Hickey & co 决定推广 Clojure 的数据表示法并发表了 EDN spec . EDN 是 Clojure 的一个子集;它仅限于 Clojure 语言的数据元素。

由于 Clojure 是一个 Lisp,并且与所有 lisp 一样,吹捧“代码就是数据就是代码”的理念,因此上述段落的实际含义可能并不完全清楚。我不确定任何地方是否有详细的差异,但仔细检查了 Clojure Reader description前面提到的 EDN 规范显示了一些差异。最明显的区别是围绕宏字符,尤其是 # dispatch 符号,它在 Clojure 中比在 EDN 中具有更多的目标。例如,#(* % %)表示法是有效的 Clojure,Clojure 阅读器将其转换为等效于以下 EDN:(fn [x] (* x x)) .对于这个问题特别重要的是几乎没有记录的 #=特殊阅读器宏,可用于在阅读器内部执行任意代码。

由于 Clojure 阅读器可以使用完整的语言,因此可以将代码嵌入到阅读器正在阅读的字符串中,并立即在阅读器中对其进行评估。一些例子可以在 here 中找到.
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 小程序看起来并不是一个很有前途的想法,尤其是因为 ClojureScript 的主要目标是将 Clojure 语言的范围扩展到 JVM(和 CLR)的范围之外。所以决定 ClojureScript 不能访问它自己的阅读器,因此也不能访问它自己的编译器(即在 ClojureScript 中没有 eval 也没有 readread-string)。更详细地讨论了该决定及其影响 here ,由一个真正知道事情如何发生的人(我不在那里,所以这个解释的历史视角可能有一些不准确)。

所以 ClojureScript 没有等效的 clojure.core/read-string (有些人会争辩说它因此不是真正的 lisp)。尽管如此,如果有某种方式在 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 通常建立在一些数据抽象(列表、向量、集合、映射和通常的标量)之上,因此打印/读取循环的默认行为是保留数据的抽象形状(映射是map),但不是特别是它的具体类型。例如Clojure有多个map抽象的实现,比如PersistentArrayMap用于小 map 和 PersistentHashMap对于更大的。该语言的默认行为假定您不关心具体类型。

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

关键是,用 *print-dup*设置为 true , pr和 family 不会产生有效的 EDN,但实际上 Clojure 数据包括一些显式 #=(eval build-my-special-type)表单,它们不是有效的 EDN。

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

关于Clojure & ClojureScript : clojure. core/read-string, clojure.edn/read-string 和 cljs.reader/read-string,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24661655/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com