Clojure Spec 解析 Reducible

发布于 2025-01-20 22:44:59 字数 557 浏览 3 评论 0原文

clojure.spec.alpha/+的文档说:

返回匹配一个或多个匹配的值 序产生匹配的向量

,我可以这样使用:

erdos=> (s/conform (s/+ (s/cat :e #{\a \b \c})) (seq "abc"))
[{:e \a} {:e \b} {:e \c}]

在下一步中,我想将其推广到可简化值而不是序列上运行。但这是行不通的:

erdos=> (s/conform (s/+ (s/cat :e #{\a \b \c})) "abc")
:clojure.spec.alpha/invalid

我如何使用clojure.spec 正则表达式操作员 在还原上而不是还原序列? (但没有创建临时序列。)谢谢!

The doc of clojure.spec.alpha/+ says:

Returns a regex op that matches one or more values matching
pred. Produces a vector of matches

And I can use it like this:

erdos=> (s/conform (s/+ (s/cat :e #{\a \b \c})) (seq "abc"))
[{:e \a} {:e \b} {:e \c}]

In the next step, I want to generalize it to run on Reducible values instead of sequences. But it will not work:

erdos=> (s/conform (s/+ (s/cat :e #{\a \b \c})) "abc")
:clojure.spec.alpha/invalid

How could I use clojure.spec regular expression operators on Reducibles instead of sequences? (but without creating temporary sequences.) Thank you!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

戒ㄋ 2025-01-27 22:44:59

您可以定义一个 conformer 将输入(例如字符串)转换为序列。使用 and 将其与对序列进行操作的规范组合在一起:

(s/def ::seq-from-string (s/conformer #(if (string? %) (seq %) ::s/invalid)
                                      #(apply str %)))


(s/conform (s/and ::seq-from-string
                  (s/+ (s/cat :e #{\a \b \c})))
           "abc")
;; => [{:e \a} {:e \b} {:e \c}]

(s/unform (s/and ::seq-from-string
                 (s/+ (s/cat :e #{\a \b \c})))
          [{:e \a} {:e \b} {:e \c}])
;; => "abc"

这是一个更多在该规范之上使用 coll-of 的复杂示例:

(s/conform (s/coll-of (s/and ::seq-from-string
                             (s/+ (s/cat :e #{\a \b \c}))))
           ["a" "bb"])
;; => [[{:e \a}] [{:e \b} {:e \b}]]

顺便说一下,我不确定为什么要避免在字符串周围创建临时序列。当从字符串创建序列时,例如(seq "abc"),轻量级序列对象StringSeq 被创建来包装底层字符串。我不认为这有什么问题。

You can define a conformer that converts the input (e.g. a string) to a sequence. Use and to compose it with the spec that operates on the sequence:

(s/def ::seq-from-string (s/conformer #(if (string? %) (seq %) ::s/invalid)
                                      #(apply str %)))


(s/conform (s/and ::seq-from-string
                  (s/+ (s/cat :e #{\a \b \c})))
           "abc")
;; => [{:e \a} {:e \b} {:e \c}]

(s/unform (s/and ::seq-from-string
                 (s/+ (s/cat :e #{\a \b \c})))
          [{:e \a} {:e \b} {:e \c}])
;; => "abc"

Here is a more complex example with coll-of on top of that spec:

(s/conform (s/coll-of (s/and ::seq-from-string
                             (s/+ (s/cat :e #{\a \b \c}))))
           ["a" "bb"])
;; => [[{:e \a}] [{:e \b} {:e \b}]]

By the way, I am not sure why you want to avoid creating a temporary sequence around the string. When creating a sequence from a string, e.g. (seq "abc"), a lightweight sequence object StringSeq gets created that wraps the underlying string. I don't see the problem with that.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文