Recursive Generation
In some situations, it is required to generate objects that can nest recursively. For example, JSON is an often used data exchange format that consists of various layers of dictionaries (with string keys) and one dimensional arrays, as well as strings, numbers, booleans an Nothing
.
In Supposition.jl, we can generate these kinds of recursively nested objects using the Data.Recursive
Possibility
. For this, we need a generator of a basecase, as well as a function that wraps one generated example in a new layer by returning a new Possibility
.
We can construct the Possibility
that generates the basecase like so:
using Supposition
strings = Data.Text(Data.AsciiCharacters())
bools = Data.Booleans()
none = Data.Just(nothing)
numbers = Data.Floats{Float64}()
basecase = strings | numbers | bools | none
Supposition.Data.OneOf:
Produces an element from one of the following with equal probability:
∘ Supposition.Data.Text(Supposition.Data.AsciiCharacters(); min_len=0, max_len=10)
∘ Supposition.Data.Floats{Float64}(; nans=true, infs=true)
∘ Supposition.Data.Booleans()
∘ Supposition.Data.Just(nothing)
which gives us a Data.OneOf
, a Possibility
that can generate any one of the objects generated by the given Possibility
.
For wrapping into new layers, we need a function that wraps our basecase Possibility
and gives us a new Possibility
generating the wrapped objects. For the JSON example, this means we can wrap an object either in a Vector
, or a Dict
, where the latter has String
keys.
Recursive
expects a function that takes a Possibility
for generating the children of the wrapper object, which you should pass into a generator. The generator for the wrapper can be any arbitrary Possibility
.
Defining that function like so:
function jsonwrap(child)
vecs = Data.Vectors(child)
dicts = Data.Dicts(strings, child)
vecs | dicts
end
jsonwrap (generic function with 1 method)
allows us to construct the Possibility
for generating nested JSON-like objects:
json = Data.Recursive(basecase, jsonwrap; max_layers=3)
example(json)
Dict{String, Union{Nothing, Bool, Float64, Dict{String, Union{Nothing, Bool, Float64, String}}, String, Vector{Union{Nothing, Bool, Float64, String}}}} with 5 entries:
"!" => -1.58772e111
"\e^Y\x1cq\bEj8" => -4.31286e-135
"^" => Union{Nothing, Bool, Float64, String}[false]
"\x0f \t;lgC\e\x15" => nothing
"Y266uYkn6" => -5.68895e-145