gen.sized / gen.recursive: size-driven depth for recursive generators #5
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Missing
Size-aware recursion helpers:
gen.sized (size: gen)to read the current size, andgen.scale f g/gen.recursive leaf nodeso a recursive generator terminates and shrinks in depth without every caller threading a depth counter.Where it was needed
jsonschema2nix generates recursive schemas (objects containing objects, lists, maps, unions of those). Every generator takes
depth: defNames:and bottoms out withif depth <= 0 then leaf else ...:Depth is fixed at 2, unrelated to the test size, so small tests are not shallower than large ones and shrinking never reduces nesting; a counterexample at depth 2 stays at depth 2.
Suggested shape
gen.sized f(Hedgehogsized),gen.scale f g,gen.small g(scale (n: n / 2)).gen.recursive leaf (self: nodes)that picks leaves at size 0 and halves the size for children, the way Hedgehog'sGen.recursivedoes.Plan
Given
Gen a = size: rng: Tree a:Straight port of Hedgehog
Gen.recursive. Nixletis lazy, so noself:parameter:genNode = gen.recursive gen.oneOf [ leaf ] [ (gen.listOf … genNode) ]refers to itself directly. Halving (issue) instead of Hedgehog's golden ratio is fine for an integer size; depth stays <= log2(maxSize).Depth shrinks only because
choose(oneOf/frequency) shrinks toward the first, i.e. leaf, alternative. That is #6 and must land first.gen.anything(#12) is the intended dogfood test.Roadmap order: #6 -> #5 -> #2 -> #1 -> #4 -> #3.
Implemented in
0bb1465, pushed to main.