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

欢迎!请查看关于页面了解这项工作的更多信息。

0
test.check

有很多生成器会返回一个序列(列表、向量、元组、映射、字符串等)。有时在生成的序列上设置大小限制,要么是最小值,要么是最大值,是有用的。不妨有一个生成器能够接受序列生成器,并确保序列的长度是特定的。以下是三个例子:
(of-length min max gen)
(of-max-length max gen) => (of-length 0 max gen)
(of-min-length min gen) => (of-length min nil gen)

of-length 检查生成序列的长度。如果太小,使用 (take min (cycle s)) 来扩展序列的长度。
如果太长,使用 (take max s) 来返回最大长度
它需要小心返回与接收到的相同类型
如果没有接收到序列,则将其视为一个包含一个元素的序列
如果 min 不是 0,使用 such-that not nil 来确保生成合适的 seq

22 个回答

0

评论者:gfredericks

大多数集合生成器已经接受用于控制其大小的选项;您是否有这样用例,那些控制不足以满足需求?

0

评论者:m0smith

我完全忽略了带:min 和:max 选项的生成器

特别是我在考虑基于字符串的生成器,因为需要填充数据库表,所以字符串必须与列定义匹配,例如非空和 varchar(15)。当我思考这个问题时,编写一个复合生成器来强制长度限制似乎比尝试改进所有生成序列结构生成器更有意义。

检查 generators.cljc 文件时发现,列表、哈希表甚至基于数组的生成器都可以使用最小值和最大值选项。

0

评论者:m0smith

如果尝试将字符串从 def 更新到 defn,以便允许为大小提供多个参数,例如

(defn string ([] (fmap clojure.string/join (vector char))) ([size] (fmap clojure.string/join (vector char size))) ([min max] (fmap clojure.string/join (vector char min max)))))

那么 (sample string) 就不再工作,但是 (sample (string))、(sample (string 5)) 和 (sample (string 3 7)) 都可以工作

是否有让“字符串”正常工作的技巧?或者修改字符串以接受多个参数是否有更好的方法?

0
评论者:gfredereicks

我认为没有一种干净的方法来解决你提到的问题,这也是我没有在这里看到明显解决方案的原因之一。

我在创建 {{large-integer}} 和 {{double}} 生成器时遇到了这个问题,我决定创建两个生成器:{{large-integer}} 是具有默认行为的生成器,而 {{large-integer*}} 是一个接受选项并返回生成器的函数。

事后看来,我不知道这是否是最好的选择,这可能很令人困惑。我向 David MacIver 询问关于他在 hypothesis(一个类似的 Python 库)中如何处理这个问题,他说他没有“任何”原始生成器,只有返回生成器的函数(有时不带参数)。我喜欢这种方法的一致性,但它显然会使 test.check(尽管有一些混搭技巧可以保留向后兼容性)发生巨大的功能拆分。

这个问题比这个工单更大。关于你显示的代码,我认为我更喜欢类似 {{gen/set}} 的 API,它使用选项映射而不是位置参数。

现在你想让我思考这个问题,我开始专注于一个巨大的功能拆分的概念,这个拆分使用混搭技巧在几个版本中保留向后兼容性,为了清理许多不一致之处。但同样,这比这个工单更大。

如果我们不能想出一个干净的最短期的方案,我在 [test.chuck|https://github.com/gfredericks/test.chuck] 的标准就会更加宽松了。

0

评论者:m0smith

你们更喜欢哪种选择?添加类似 of-length 来限制现有的 seq 生成器,还是创建 (def string ...) 和 (defn string* ...)?我刚刚完成了 TCHECK-97 的 Unicode 实现,因此我将遵循我们决定的任何模式。

0

评论者:gfredericks

我们有至少三个字符串生成器吗?你是在考虑为每一个都提供替代方案吗?

0
_评论人:m0smith_

这是我提出此请求的初衷。我们真的想要将字符串生成器的数量翻倍吗?更不用说其他像数组等东西了。

另一个想法是添加一个单独的新生成器,to-string,它可以接受不同的字符生成器,并使用它根据元素生成器创建字符串


 (defn to-string
   ([element-gen] (to-string element-gen {})))
   ([element-gen [{:keys [num-elements min-elements max-elements max-tries ] :or {num-elements nil min-elements 0 max-elements nil max-tries 10}}]
                   (fmap clojure.string/join (vector char-gen ==apply-options==))))


我省略了处理选项的代码,但希望你们能理解这个想法。

可以像  (to-string char {:min-elements 5 :max-elements 10})  或 (to-string char-ascii {:num-elements 5})  这样来调用它

这样就可以添加新的字符生成器,它们可以轻松地转换为字符串。
0
_评论人:m0smith_

看起来,coll-distinct-by 几乎完全符合我的需求,但 allow-dups? 标志却没有按照我预期的来做。

(sample (coll-distinct-by [] identity true  false (elements [\a \b \c \d \e الحكومة ]) {:num-elements 4})) 即使 allow-dups? 为 true,仍然总是返回不同的元素
0

评论者:gfredericks

{{coll-distinct-by}} 非常专业,可能在这里不适用。

我认为你可以很容易地将 (link: num-elements min-elements max-elements) 翻译成 gen/vector 使用的参数。max-retries 不应该适用。

像 {{to-string}} 这样的功能可能很好,特别是如果它与你对 TCHECK-97 的想法相匹配(例如,TCHECK-97 为 {{to-string}} 提供参数)。

0

评论者:m0smith

使用 git --no-pager diff master feature/TCHECK-99 生成的补丁,在 https://github.com/m0smith/test.check.git

0

评论者:m0smith

忽略那个补丁。我落后于 master 很远了。一个新的补丁已经在路上

0

评论者:m0smith

在将我的分叉与 test.check 同步后,生成了 TCHECK-99-2.patch。应该是最新的。

0
_评论人:m0smith_

我还考虑过如何允许一个函数具有生成器的行为。可以向函数添加一个 :generator-factory 元数据,如

(defn to-string
"生成元素生成器字符串,默认为字符"
{:generator-factory to-string}
([] (to-string char {})))
   ([element-gen] (to-string element-gen {})))
([element-gen [{:keys [num-elements min-elements max-elements]}]
                   (fmap clojure.string/join (vector char-gen ==apply-options==))))


生成器可以更新为接受任何具有 :generator-factory 元数据的对象
call-gen 可以更新为查找新的元数据,如果存在,则调用相关函数并将结果用作生成器。

0

评论者:gfredericks

是的,这基本上是我对保留向后兼容性所设想的想法——元数据生成器将有一些形式的弃用警告。

0
_评论人:m0smith_

另外,在 to-string,clojure.string/join 支持一个分隔符,可以轻松地添加为一个额外的选项,如

(to-string int {:sep ","})

如果你对此满意,我将更新补丁。
...