Generic recursion over any Ichor.Backtrack.Term implementation --
extracted from a pattern independently duplicated inside
Ichor.Toolkit.TypeScheme itself: resolve_deep/3 and the private
substitute/3 shared the identical "apply a transform, then (if the
result is compound) deconstruct, recurse into every argument with the
same transform, and reconstruct" recursive skeleton, differing only in
what the transform itself does at each step (chase a variable's
binding one level, or substitute a specific variable for a fresh one);
free_vars/3 is the same recursive shape again, but folding into an
accumulator instead of rebuilding a term.
Neither function here knows anything about bindings, substitutions, or
types -- only what variable?/1, compound?/1, deconstruct/1, and
(for rewrite/3) reconstruct/2 say about a given term_module, the
same boundary Ichor.Backtrack.Bindings.unify/4 already draws.
Summary
Functions
Folds over term and every subterm reachable through compound?/1/
deconstruct/1, visiting a node before its children (order doesn't
matter for a commutative combine, e.g. collecting a set of variable
ids -- Ichor.Toolkit.TypeScheme.free_vars/3's own use).
Applies transform to term, then -- if the result is compound --
deconstructs it and recurses into every argument with the same
transform, reconstructing afterward. transform is applied exactly
once per node, on the way down, never re-applied to a freshly
reconstructed compound -- correct for a transform that only ever acts
on non-compound nodes (resolving or substituting a variable; a
compound term is rebuilt from its already-transformed arguments, never
itself examined), which is the only shape resolve_deep/3/substitute/3
ever needed. Not a general bottom-up rewrite pass (e.g. constant
folding, which needs to re-examine a parent after its children
change) -- transform never sees a node built by this same call.
Functions
Folds over term and every subterm reachable through compound?/1/
deconstruct/1, visiting a node before its children (order doesn't
matter for a commutative combine, e.g. collecting a set of variable
ids -- Ichor.Toolkit.TypeScheme.free_vars/3's own use).
Applies transform to term, then -- if the result is compound --
deconstructs it and recurses into every argument with the same
transform, reconstructing afterward. transform is applied exactly
once per node, on the way down, never re-applied to a freshly
reconstructed compound -- correct for a transform that only ever acts
on non-compound nodes (resolving or substituting a variable; a
compound term is rebuilt from its already-transformed arguments, never
itself examined), which is the only shape resolve_deep/3/substitute/3
ever needed. Not a general bottom-up rewrite pass (e.g. constant
folding, which needs to re-examine a parent after its children
change) -- transform never sees a node built by this same call.