Turns ruleset modules into a Rete.Network.
Internal. The DSL front end already ran at compile time inside each defrule.
What is left at build time is the part that depends on the whole set of rules:
Rete.Compiler.Negation rewrite compound negations into helper productions
disambiguate_codes/1 qualify an expression code two modules disagree on
Rete.Compiler.BetaGraph build the beta nodes, sharing them where possible
Rete.Network group conditions into alpha nodes, index the taxonomyNode sharing is why this cannot happen per rule. Whether two conditions collapse onto one node depends on what every other rule already put in the graph.
Cross-module expression codes. A code is equal exactly when two expressions behave
the same โ with one hole. An unqualified call hashes as the bare name. So two modules
that each define ok?/1 differently produce the same code for
{:bar, amt} when ok?(amt).
Rete.DSL.Codegen clears Rete.IR.Expr's :share for such an expression, while
the AST and the caller's environment are still in hand. This qualifies a code the front end
did not mark shared, and that more than one module contributed, as <code>@<module>, before building
anything from it.
Everything else is shared across modules, because nothing left in it can differ. Aliases
resolve to the module they name, @x carries its defining module, and a pin is
unwrapped โ all before hashing. See docs/design/ir.md ยง5. So two modules that write
{:customer, cid} match it once per fact, not once each.
Sharing within a module is untouched. Getting a cross-module share wrong is silent
corruption, so :share defaults to false and only a positive answer shares.
Summary
Functions
Builds a network from ruleset modules.
Builds a network from productions directly, bypassing module aggregation.
Qualifies every unshared expression code that more than one module contributed.
The beta graph of a network, for inspection.
Functions
@spec build( [module()], keyword() ) :: Rete.Network.t()
Builds a network from ruleset modules.
Options go to Rete.Taxonomy.new/2. :fact_type_fn is the one that matters, and it
defaults to struct, tagged tuple and tagged map.
Rete.Compiler.build([MyRuleset])
Rete.Compiler.build([MyRuleset, OtherRuleset], fact_type_fn: &MyApp.type/1)
@spec build_productions([Rete.IR.Production.t()], [tuple()], keyword()) :: Rete.Network.t()
Builds a network from productions directly, bypassing module aggregation.
Useful for testing a set of productions without a ruleset module per case.
@spec disambiguate_codes([Rete.IR.Production.t()]) :: [Rete.IR.Production.t()]
Qualifies every unshared expression code that more than one module contributed.
If only one module produces an expression's code, this leaves it alone. So nothing changes for a single-module network. See the module doc for when a shared code can be trusted across modules and when it cannot.
This is exposed so a test can check the disambiguation, without building a network.
@spec graph(Rete.Network.t()) :: Rete.Compiler.BetaGraph.t()
The beta graph of a network, for inspection.