Rete.Compiler.Negation (Rete v0.1.0)

Copy Markdown View Source

Turns a Rete.IR.CompoundNegation into something a Rete network can express.

Internal. A negation node watches one condition and propagates its token while nothing matches. It cannot watch a conjunction, and de Morgan does not rescue it: the conjuncts share existentially quantified variables, so with orders {1} and refunds {2}, "no x has both" is true and the rewrite is false.

So the conjunction is lifted into a generated helper that inserts a marker fact, and the compound negation becomes an ordinary negation of that marker:

defrule clean({:customer, cid}, {:nand, [{:order, cid}, {:refund, cid}]})

# becomes, in effect
defrule clean__neg_1({:customer, cid}, {:order, cid}, {:refund, cid}) do
  {:"clean__neg_1", %{cid: cid}}
end
defrule clean({:customer, cid}, {:not, [{:"clean__neg_1", cid}]})

Three things make that correct. The marker carries the bindings the conjunction joins on, or one customer with both would suppress the rule for every customer. The helper repeats the preceding conditions, which is what binds those variables. And the helper fires first, through an :internal_salience set to the nesting depth, so extraction chains correctly and the negating rule never observes an absence that had merely not been computed yet.

A helper's expressions are plain closures, because extraction runs at build time, long after macro expansion. See docs/design/network.md §6.

Summary

Types

A production and the helper productions extracted out of it.

Functions

Rewrites every compound negation in a production.

Whether a production was generated by extraction rather than written.

Types

extraction()

@type extraction() :: {Rete.IR.Production.t(), [Rete.IR.Production.t()]}

A production and the helper productions extracted out of it.

Functions

extract(production)

@spec extract(Rete.IR.Production.t()) :: extraction()

Rewrites every compound negation in a production.

Returns the rewritten production and the helpers it generated, in the order they must be added to the network. Helpers are extracted depth first, so a compound negation nested inside another appears before the helper that negates it.

A production with no compound negation is returned unchanged with [].

generated?(production)

@spec generated?(Rete.IR.Production.t()) :: boolean()

Whether a production was generated by extraction rather than written.