- A program consists of a set of rules and a set (sometimes called the state or fact pool) of objects.
-
A rule is written in the form of
A1, A2, ..., An ==> B1, B2, ..., Bn, with the left-hand side called the precond (short for precondition) and the right-hand side called the postcond (short for postcondition). This means that whenever the state containsA1andA2and etc., these objects are removed from the state and replaced with objectsB1,B2and etc.. Any of the two sides of any rule can be empty. -
The initial fact pool is written in the form of
[ obj1, obj2, ..., objn ]. This is optional. If a program does not specify an initial fact pool, an empty fact pool would be assumed. -
The order in which the objects appear does not matter. For example,
A, B ==> Cis the same asB, A ==> C, and[ A, B ]is the same as[ B, A ]. -
The facts can be compound, in which case they are actually tuples and are written in the form of
Head(Arg1, Arg2, ..., Argn). Rules can be written to match parts of these tuples, making it much more convenient to represent and manipulate facts that represents complicated concepts (e.g. reachability from one place to another); see below. -
One can specify to match a group of possible compound facts in the precond of a rule by specifying variables at certain locations; these variables are names that starts with a question mark
?. For example:- The precond
path(?a, ?b)matches any compound fact that is of the formpath(A, B)(e.g.path(a, b)andpath(c, d)) - The precond
path(?a, b)matches any compound fact that is of the formpath(A, b)(e.g.path(a, b),path(b, b),path(c, b)) - The precond
path(?a, ?a)matches any compound fact that is of the formpath(A, A)(e.g.path(a, a),path(b, b),path(c, c))
path(?a, ?b), path(?b, ?c)would match any two facts of the formpath(A, B)andpath(B, C)and would not be fired if the fact pool only contains, for example,path(a, b)andpath(a, c). - The precond
- The rules are (currently) checked from top to bottom according to the order they appear in the source code. Rules that comes earlier gets matched first.
-
If a rule produces the object
#HALT, the whole execution is stopped immediately after the full execution of that rule. -
A rule that does not "consume" its precond from the fact pool is called a producing rule, since it's commonly used to produce (infinitely, as long as the rule is being matched and scheduled for execution) objects. This kind of rules are written in the form of
A1, A2, ..., An +=> B1, B2, ..., Bn, and is equivalent toA1, A2, ..., An ==> A1, A2, ..., An, B1, B2, ..., Bn. -
A rule that only executes once during the entire time is called a fire-once rule. This kind of rules are written in the form of
A1, A2, ..., An 1=> B1, B2, ..., Bn. -
"Fire-once producing rule" exists and it's written in the form of
A1, A2, ..., An 1+=> B1, B2, ..., Bn.+1=>is a syntax error - it must be written as1+=>. -
You can chain multiple rules together as long as the postcond of one rule is exactly the precond of the next rule, i.e. for any
A x B y C ... Y w Zis equivalent toA x B; B y C; ...; Y w ZwhereA,B, ...,Zare preconds and postconds andx,y, ...,ware arrows (i.e.==>,+=>,1=>and1+=>). - Single-line comments are started with two slashes
//. There's no multi-line comments.
One may have their doubt about its capability of calculation; it can at least perform simple arithmetic operations and looping. This program calculates the n-th number in the Fibonacci sequence (starting from 1 with fib(1) = 1 and fib(2) = 1) with the input n set to be the number of a in the initial fact pool:
a, _calc ==> _add;
cnt2, _add ==> cnt2_1, cnt2_2, _add;
cnt1, _add ==> cnt3, _add;
cnt2_1, _add ==> cnt3, _add;
_add ==> _move;
cnt2_2, _move ==> cnt1, _move;
cnt3, _move ==> cnt2, _move;
a, _move ==> a, _calc;
_move ==> _coalesc;
cnt1, _coalesc ==> res, _coalesc;
_coalesc ==> ;
// calculate fib(8)
[ a:8, cnt2, _calc ]