metosin/malli

Adding frequencies to `:or`-like schemas for generation

Open

#449 创建于 2021年5月14日

在 GitHub 查看
 (3 评论) (0 反应) (0 负责人)Clojure (237 fork)batch import
enhancementhelp wanted

仓库指标

Star
 (1,724 star)
PR 合并指标
 (30 天内没有已合并 PR)

描述

The kind of PR I am suggesting would solve two issues at once. Open to debate of course, but we could have something like this:

;; Variant A
[:orn {:gen/freq {::int 2 ::keyword 1}}
 [::int :int]
 [::keyword :keyword]]
 
;; Variant B
[:orn
 [::int :int 2]
 [::keyword :keyword 1]]                 

First, the goal is to generate an output that would be more realistic by following frequencies. In this example, I assume that a realistic output would be of having ints twice as often as keywords.

Second, that can act a mechanism for preventing exponential explosion when recursive definitions are at stake. Suppose this very simple use case. Real ones I routinely encounter are much more complex and this problem is very quickly blown out of proportion:

(malli.gen/generate [:schema
                         {:registry {::data [:or ::int [:ref ::vec]]
                                     ::int :int
                                     ::vec [:vector ::data]}}
                         ::vec]
                        {:size 3})

See how small the size must be. Try with 10 and see how large the output becomes on average. It is easy to go a bit further, adding more recursive definitions, and then, even a size of 1 becomes problematic. Instead, I could specify frequencies in ::data so that ::vec happens less often and that would be a very effective solution in order to prevent that kind of exponential explosion.

Implementation-wise, I believe it would be fairly simple. As simple as writing a simple -orn-gen function in malli.generator and slightly modifying -multi-gen. I am targeting :orn because we need a way for referring to children by name.

If you approve the idea and we settle on a notation, I can PR it. I favor variant A. Albeit it forces a bit of extra typing, it is absolutely clear that this is about generation and not validation.

Having such a :gen/freq property would mean using test.check's frequency generator instead of one-of. Default frequency would be 1.

贡献者指南