- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我不清楚所有这些读取字符串函数之间的关系。嗯,很明显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 数据,还是...?
The read and read-string functions are located in the cljs.reader namespace
最佳答案
简介: Clojure 是 EDN 的超集。默认情况下,pr
, prn
和 pr-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
也没有 read
和 read-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/
为什么该语言的名称是“Clojure”? 我用谷歌搜索了一下,在#clojure 中询问。到目前为止,还没有运气。 最佳答案 Rich Hickey(他是 Clojure 的设计者)对此的评论是 wi
我不明白为什么升级后会出现以下编译错误: Compiling addr-verify.core Exception in thread "main" java.lang.NoClassDefFound
我试图将从映射操作返回的(惰性)序列传递给另一个映射操作,以便我可以在第一个序列中查找元素。代码从文本文件(以行/列格式)解析一些足球装置,清理它,然后返回一张 map 。 这是代码: (ns fix
我想过滤一组,例如: (filter-set even? #{1 2 3 4 5}) ; => #{2 4} 如果我使用clojure.core/filter我得到一个不是集合的seq: (filte
(defn hi[](+ 5 6)) (hi) (defn hi[](+ 6 7)) (hi) 你好,我是 clojure 的新手。如上所述,我编写了两个具有相同名称的函数。我们可以在 cloj
我按照这个伪代码递归地将十进制转换为二进制。 findBinary(decimal) if (decimal == 0) binary = 0 else binar
我正在尝试学习 Clojure 并尝试定义这个简单的函数: user=> (defn triple [arg] (* 3 arg)) #'user/triple user=> (triple 1) 3
是->和 ->>宏只是为了使代码更具可读性还是它们还有其他特定功能? 最佳答案 线程优先( -> )和线程最后( ->> )是为了使代码更具可读性。但这已经很重要了! 它允许取消嵌套函数调用(示例取自
我在 http://www.learningclojure.com/2010/11/yet-another-way-to-write-factorial.html 上找到了这个代码,但我不明白 pop
我正在阅读 Programming Clojure 2nd edition,在第 49 页它涵盖了 Clojure 的 for 循环结构,它说它实际上是一个序列理解。 作者建议使用以下代码: (def
Clojure 中有双端队列吗?我的印象是 Clojure 的 PersistentQueue 是单端的(我错了吗?)。我需要能够从队列的任一端删除(即“pop”)和“peek”数据。我所说的双端队列
换句话说,有没有办法在看起来不像 (MACRO arg* ...) 的表单上触发宏扩展? . 举一个假设的例子: (defmacro my-var (do (printf "Using my-va
我很难理解懒惰。 有人能帮我理解为什么我下面的函数不是懒惰的吗 (defn my-red ([f coll] (my-red f (first coll) (rest coll) ))
在 Clojure 核心中决定参数函数顺序的规则是什么(如果有的话)? 类似 map 的函数和 filter期望数据结构作为最后一个 争论。 类似 assoc 的函数和 select-keys期待数据
我在 clojuredocs 上遇到过 completing 函数,但目前没有文档。 你能提供一些例子吗? 最佳答案 completing 用于扩充可能没有具有一元“完成”元数的一元重载的二元归约函数
这个现在支持吗?我能找到的唯一信息是来自维基的示例( https://github.com/clojure/core.match/wiki/Deftype-and-defrecord-matching
我正在关注“Clojure in Action”,对此我感到困惑: (defn with-log [function-to-call log-statement ] (fn [& args
对于下面的代码,箭头是宏还是函数名称中的简单字符? (来自 here) (defn file->map [file] ;; TODO ) 最佳答案 箭头是函数名称的一部分。有一个函数定义,不是
Clojure 的 range函数包含来自 start独家在end (如果提供)。核心库中是否有一个函数可以提供完全包含(开始和结束)的范围? 我发现在某些情况下必须调整最终值的代码 - 例如向下而不
当我尝试从 REPL 运行以下代码时(使用动态记录): (defrecord (symbol "rec2") (vec (map symbol ["f1" "f2"]))) 我收到错误 Compile
我是一名优秀的程序员,十分优秀!