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) 返回最大长度
返回类型需要与其接收到的类型相同
如果不接收一个序列,则将其视为一个元素序列。
如果 minimum 不是 0,使用 such-that not nil 确保生成了一个正确的 seq。

22 个答案

0

评论由:gfredericks

大多数集合生成器已经接受用于控制其大小的选项;有没有特定的用例,其中这些控制不足?

0

评论由:m0smith

我完全错过了带:min 和:max 选项的那些

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

简短地检查了 generators.cljc,其中 list、hash-map 以及基于数组的生成器都可用 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(尽管有一些狡猾的技巧可以保留向后兼容性)。

这个问题比这个工单要大得多。关于您提供的代码,我认为我更喜欢像 {{gen/set}} 那样的 API,使用选项映射而不是位置参数。

现在你让我思考这个问题,我开始痴迷于一个大的中断性 API 变更的想法,使用狡猾的技巧来保留几个版本的向后兼容性,以清理许多不一致性。但同样,这比这个工单要大。

如果我们不能提出一个干净的短期解决方案,我在 [test.chuck|https://github.com/gfredericks/test.chuck] 中的接受标准要宽松得多 ☺。

0

评论由:m0smith

你们更倾向于添加什么,是以-of-length为长度的限制现有序列生成器,还是创建(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-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
_由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
by

评论由:m0smith

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

0
by

评论由:m0smith

忽略那个补丁。我对 master 来说已经过时了。新的补丁即将到来

0
by

评论由:m0smith

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

0
by
_由m0smith发表的评论

我还考虑了如何让一个函数表现得像生成器。例如,给一个函数添加诸如

(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
by

评论由:gfredericks

是的,这基本上就是我提出的保留向后兼容性的想法——元数据生成器将附有某种弃用警告。

0
_由m0smith发表的评论

此外,在toString中,clojure.string/join支持一个分隔符,我们很容易将其作为一个附加选项添加,如

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

如果你们同意,我将更新补丁。
...