Rete.Compiler (Rete v0.5.0)

Copy Markdown View Source

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 taxonomy

Node 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

build(modules, opts \\ [])

@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)

build_productions(productions, taxo_data \\ [], opts \\ [])

@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.

disambiguate_codes(productions)

@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.

graph(network)

The beta graph of a network, for inspection.