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 来确保生成正确的序列。

22 个答案

0

评论者:gfredericks

大多数集合生成器已接受用于控制其大小的选项;您是否考虑过,那些控制是否足够用?

0

评论者:m0smith

我完全错过了那些接受":min"和":max"选项的生成器。

特别是在考虑字符串生成器时,因为需要填充数据库表,所以字符串必须与列定义匹配,比如非空和变量字符(15个字符)。当我思考这个问题时,似乎创建一个组合生成器来强制长度限制比试图进行所有生成序列结构生成器的缓解改造更为合理。

简要查看generators.cljc文件显示,列表、哈希映射甚至基于数组的生成器都可以使用min和max选项。

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))都工作

有没有什么技巧可以让“string”本身工作?或者有没有更好的方法来修改string以接受多个参数?

0
_由 gfredericks 评论

我认为没有干净的解决方案可以解决你提到的问题,这也是为什么我没有看到明显的解决方案。

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

事后再来看,我不确定这是否是最优选择,因为它有些令人困惑。我向David MacIver询问了他在hypothesis(一个类似Python库)中是如何处理的,他说他没有任何原始生成器,只有返回生成器的函数(有时不带参数)。我喜欢这种方式的一致性,但它显然会对test.check造成很大的破坏性变化(尽管有一些巧妙的技巧可以保留向后兼容性)。

这个问题比这个工单要大。关于你提供的代码,我认为我更倾向于那些具有选项映射的API,类似于{{gen/set}},而不是位置参数。

现在我开始思考这个问题,我开始对一个大型的破坏性API变革着迷,该变革使用一些技巧来保持几个版本的向后兼容性,以便清理大量不一致性。但又一次,这比这个工单要大。

如果我们想不出一个干净的中期对策,在[gfredericks/test.chuck|https://github.com/gfredericks/test.chuck]的接受标准会宽松得多 ☺。

0

评论者:m0smith

您更喜欢哪种方式?是通过添加类似of-length这样的功能来限制现有的序列生成器,还是创建(def string ...)和(defn string* ...)?我刚刚完成了TCHECK-97的Unicode实现,因此我会遵循我们决定的任何模式。

0
by

评论者:gfredericks

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

0
by
评论者: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-retries 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
by
评论者: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
by

评论者: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

TCHECK-99-2.patch 补丁是在将 my fork 上的 test.check 同步后生成的。应该是最新的。

0
评论者:m0smith_

我还想了一下如何在允许一个函数像生成器一样运行。给一个函数添加 :generator-factory 元数据,例如:

(defn to-string
"生成元素-gen 的字符串,默认为字符"
   {: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 ","})

如果这没有问题,我将更新补丁。
...