Everything that changes while rules fire, as one value threaded through the loop.
Internal. A node is a function of state. It returns the state, plus the work it
produced. The loop does the walking. This keeps propagation flat, and it leaves one
place where listener events are emitted. See docs/design/engine.md §1.
:listeners is [{module, state}] rather than a map, so listeners see events in
attachment order and one module can be attached twice with different state.
Summary
Functions
Takes the next unit of work, or :empty.
Appends propagation work.
A state over a network, with empty memory and nothing pending.
Types
@type op() :: {:left | :left_retract, term(), [Rete.Token.t()]} | {:right | :right_retract, term(), [Rete.Element.t()]} | {:retract_facts, term(), [term()]} | {:event, Rete.Listener.event()}
A unit of pending propagation.
:left carries tokens from a parent. :right carries elements from an alpha.
The last two are work a node produces, but cannot carry out where it happens. A retraction has to re-enter the alpha network. Telling a listener is not a node's business either.
@type t() :: %Rete.Engine.State{ agenda: Rete.Agenda.t(), fired: non_neg_integer(), listeners: [{module(), term()}], memory: Rete.Memory.t(), network: Rete.Network.t(), order: %{required(term()) => non_neg_integer()}, queue: :queue.queue(op()) }
Functions
Takes the next unit of work, or :empty.
Appends propagation work.
@spec new(Rete.Network.t()) :: t()
A state over a network, with empty memory and nothing pending.
:order is the compile position of each production, so two activations of equal
salience fire in the order the rules were written.