2024 Clojure 状态调查!中分享您的想法。

欢迎!请查阅关于页面了解有关如何使用本站的一些更多信息。

0
test.check
我正在阅读John Hughes的《QuickCheck:从娱乐到盈利的测试》论文中的示例。我希望那些测试中生成的结构看起来像这样
 
 [:apply `reg [(gen-name) (gen/elements pids)]]

而不是现在必须表达的方式

 (gen/tuple (gen/return :apply) (gen/return `reg) (gen/tuple (gen-name) (gen/elements pids)))

我认为可以使用一个简单的递归函数来生成这些(当然,目前生成器创建的是:{:gen #<fn...>}这样的地图,我建议将其改为记录,以便我们可以区分生成器和数据结构映射)。

这已经在Quvig QuickCheck中得到了很好的实现

bq. 在一般情况下,Quviq QuickCheck 允许任何包含嵌入生成器的数据结构用作相同形状的数据结构生成器的生成器——这对用户来说非常方便,但在Haskell中,通常会在数据结构中嵌入生成器而导致类型错误。这种技术被Ericsson编写生成的生成器广泛应用于。-- Hughes

9 个答案

0

评论者:pangloss

在今天的REPL实验中,我找到了以下代码,可以将任意字面量转换为生成器

`
(defprotocol LiteralGenerator
(-literal->generator [literal]))

(defn literal->generator [literal]
(cond

(satisfies? LiteralGenerator literal) (-literal->generator literal)
(vector? literal) (apply gen/tuple (mapv literal->generator literal))
(and (map? literal) (= [:gen] (keys literal)) (fn? (:gen literal))) literal
(map? literal) (gen/fmap (partial into {}) (literal->generator (mapv vec literal)))
(set? literal) (gen/fmap set (literal->generator (vec literal)))
(list? literal) (gen/fmap (partial apply list) (literal->generator (vec literal)))
:else (gen/return literal)))

`

Some text has been omitted.

`
(defn record->generator
([record]
; Is there a better way to do this?
(let [ctor (eval (read-string (str "map->" (last (clojure.string/split (str (class record)) #"\.")))))

 (record->generator ctor record)))

([ctor record]
(gen/fmap ctor (literal->generator (into {} record)))))
`

Which enables me to extend a record like this

(记录定义 Foo [a b] LiteralGenerator (-literal->generator [this] (record->generator map->AbcDef this)))

我还没有考虑将这段代码整合进 test.check 的可能性。在进一步推进之前,我想听听大家对目前成果的反馈。

0
提交者:

评论者:reiddraper

所以,我对此有些矛盾的感觉。我同意这样做确实方便,但我也担心过于宽松可能会让更多的事故发生,并且并没有强制用户区分值和生成器。例如,如果你做了这样的事情:{{[int int]}},你是想输入{{[gen/int gen/int]}},还是你真的想要写{{[(gen/return int) (gen/return int)]}}等价的内容?如果每个期望生成器的函数也可以接受值,我们就无法再开始添加错误检查来确保正确传递生成器。同样,我也看到使用数据结构字面量的好处。如果我们写一个必须使用这种语法的函数来创建生成器,比如:{{(gen/literal [:age gen/int])}}。这样你就可以选择是否使用这种语法,但只限于 gen/literal 的作用域内?

0
提交者:

评论者:pangloss

我同意这是一个担忧,因为你无法保证看到生成器的输出,所以最好在使用 gen/literal 时明确指出。这仍然是一个不错的解决方案。幸运的是,这正是我所写的内容!我们只需将 literal->generator 重命名为 {{literal}} 并将其安装到 clojure.test.check.generators 命名空间中即可。

0
提交者:

评论者:reiddraper

我想第一步是将生成器改为使用记录。你有兴趣为此制作一个补丁吗?

0
提交者:
_评论者:pangloss_

一个非常简单的补丁,使用 Generator 记录而不是简单的 {:gen ƒ) 映射。
0
_由 reiddraper 发表的评论_

我在 ef132b5f85a07879f01417c9104aa6dea771fdb4 拉取中应用了 record-patch。谢谢。我还添加了一个 {{generator?}} 辅助函数。
0

由 ppotter 发表的评论

我发现了一件事,看起来很相关:ztellman/collection-check 定义了一个(链接:https://github.com/ztellman/collection-check/blob/07ee38e780d54088751dd4834ef9a30866ac5e2d/src/collection_check.clj#L16-L22 文本:tuple*)函数,类似于 gen/tuple,但会自动使用 gen/return 包装字面量。

值得注意的是,尽管没有解决一般情况,但这将解决了问题描述中的示例。

0

由 gfredericks 发表的评论

现在有一个针对此目标的库: https://github.com/holguinj/jen

0
参考: https://clojure.atlassian.net/browse/TCHECK-19 (由 pangloss 报告)
...