ConvergeArgs.jl Documentation

Helper library for composable, recursive sets of keyword arguments. It takes some inspiration from Nickel, although it puts more emphasis on the merging and lazy evaluation mechanics than contracts.

Use cases

Use this package if you have multiple functions which take similar interdependent keyword arguments. For example, a plotting function might take line_color and marker_color (specific), but also zlevel, color_cycle and opacity (general) as arguments. The goal of ConvergeArgs is to make it easy to write these kinds of functions in a repitition-free way.

Examples

Plotting functions

# "layers" can be NamedTuples or Dict{Symbol}s
const plotting_defaults = (zlevel=0, color_cycle=tab10, opacity=1.)
# arguments can depend on each other using "instructions"
# here, `line_color` gets set to the first color of the color cycle by default
# and `marker_color` gets set to `line_color` by default
const line_plot_defaults = Dict(
    :line_color => @instr(color_cycle->color_cycle[1]),
    :marker_color => @instr(line_color->line_color),
)

function line_plot(ax, data; kwargs...)
    kwargs = mkconfig(
        # defaults for all plotting functions
        plotting_defaults,
        # line plot comes with its own defaults
        line_plot_defaults,
        # the axis might contain some overrides for default line width etc.
        get_config(ax),
        # finally, the user might be supplying overrides
        kwargs
    )
    # … do the plotting …
end

Implementation

ConvergeArgs.mkconfigFunction
mkconfig(layers...)

Make a NamedTuple from the given layers, where each layer is a NamedTuple or Dict{Symbol} and may contain Instructions, which are evaluated.

ConvergeArgs.convergeFunction
converge(f, x)

Return the fixpoint that applying f to x iteratively converges to.

Examples

julia> converge(x -> x/2, 1.)
0.0
ConvergeArgs.eval_recMethod
eval_rec(x, id, global_context)

Evaluate x and its contents, descending into data structures as necessary. In particular, resolve any Instructions if possible.

id::Vect{Symbol} is the identifier or “url” of x in global_context. This is useful to identify infinite recursion.

Implementation

If no transformations take place, eval_rec(x, id, global_context) must be equal (==) to x. eval_rec should not modify x.

Examples

Top-level should call like this: d = eval_rec(d, [], d)

julia> c = (foo=1, bar=2)
(foo = 1, bar = 2)

julia> eval_rec(c, [], c) == c  # no Instruction → nothing changes
true

julia> c1 = rmerge(c, (bar=(@instr foo->2*foo), baz=(@instr bar->2*bar)))
(foo = 1, bar = Instruction([[:foo]], var"#17#19"()), baz = Instruction([[:bar]], var"#18#20"()))

julia> c2 = eval_rec(c1, [], c1)
(foo = 1, bar = 2, baz = Instruction([[:bar]], var"#18#20"()))

julia> eval_rec(c2, [], c2)
(foo = 1, bar = 2, baz = 4)
ConvergeArgs.rmergeMethod
rmerge(left, right)

Recursively merge left and right. If a merge is not possible, override values in left with values in right, but try to preserve the type of left.