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

欢迎!请查阅关于页面获取更多关于此操作的信息。

0
test.check
我正在研究John Hughes的“QuickCheck Testing for Fun and Profit”论文中的某些示例。我希望在测试中生成的结构看起来像这样
 
 [: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中却是不可能的,在Haskell中,在数据结构中嵌入生成器通常会导致类型错误。这种技术在爱立信编写的所有生成器中都有应用。 -- 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)))

`

将记录生成是可能的一般用途,所以我将其添加为功能

`
(defn record->generator
([record]
; 有没有更好的方法来做这件事?
(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)))))
`

这样我就可以扩展记录,如下所示

定义了名为 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_ 发布

一个使用生成器记录而不是简单的 {:gen ƒ) map 的非常简单的补丁。
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*)fn类似于gen/tuple,但自动用gen/return包装字面量。

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

0

评论者:gfredericks

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

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