|
nb.syn - NodeBrain Syntax |
|
command ::= [context. ] verb body [;] verb ::= declare | define | assert | alert | source | ... declare term decType declaration decType ::= identity | brain | module | skill | calendar define term defType definition defType ::= cell | expert | on | if | when | macro | ... define term cell [cellExpression] define term expert [skillSpecification] define term (on|if|when)(cellExpression) ... (assert|alert) term=cellExpression[, ... ] |
|
This manual page introduces the syntax and structure of the NodeBrain language used in configuration files and event streams. From this, you should be able to read a configuration file or event stream and get a general idea of the knowledge it conveys to NodeBrain. However, if you need to create or maintain complicated rule sets, you will need to reference the NodeBrain User’s Guide, available at http://www.nodebrain.org. Here we will try not to be rigorous, relying mostly on examples to give you the general idea. |
|
NodeBrain is a declarative language, in contrast to a procedural language like most programming languages you know. This means you would not want to use NodeBrain for most tasks you can perform with your favorite scripting language. For example, you would NOT use NodeBrain to read a file, extract information, and produce a report. Instead, the NodeBrain language is intended simply to provide rules and assertions to a NodeBrain agent. |
|
To some degree, it is helpful to think of NodeBrain commands as "transactions", because commands may come from multiple sources (peers, queues, FIFO’s, etc.) as individual units of work. The interpreter processes commands in whatever order they arrive from these command streams. The SOURCE command provides a way to process a complete file of commands as a single unit of work, but you should think of a SOURCE command as a single transaction. Commands are all coded as a single line of text. There is no provision for extending a command beyond the end of one line and onto the next. We sometimes break a command into multiple lines in examples for readability, but this is not supported by the interpreter. |
|
You can think of NodeBrain cells somewhat like the cells in a spreadsheet. They have definitions (formulas) and values. The major difference is the way in which cells are referenced. In a spreadsheet, cells are referenced by absolute or relative row and column. In NodeBrain, a cell is referenced by name, or by the experssion (formula) that determines the value. In fact, a named cell is really two cells---one that references another. The following example uses 11 cells: a, 1, b, 2, c, 3, x, b*c, a+b*c, y, and b*c+3. It is important to understand there is only one b*c cell, and there are two cells that reference it: a+b*c and b*c+3. define a cell 1; define b cell 2; define c cell 3; define x cell a+b*c; define y cell b*c+3; When the value of a cell changes, the new value is "published" to the referencing cells that have "subscribed" to its value. Let’s look at what happens when we assert a new value for c. assert c=4; If we assume all terms have subscribed to the values of their defining formulas (we will not go into alternatives here), then the value of x and y automatically change from 7 and 9 respectively to 9 and 11 respectively. There is an intermediate step where the value of the cell b*c changes from 6 to 8. This should give you an idea of how NodeBrain cells are defined by expressions, and how they respond to changes. This is important because the whole goal of NodeBrain is to be able to respond appropriately to new information given a set of existing knowledge. We used an arithmetic example above, but NodeBrain is perhaps more interested in logical expressions. define a cell 1; define b cell 0; define c cell a and b; # c=0; define d cell a or b; # d=1; define e cell not a; # e=0; Parentheses are used to control the order of precedence on the operators. It is best to use them when it may be unclear which operation will be performed first. define x cell (((a+b)*c)>5 or a*b>20) and d; A cell may have a real number value (e.g. 1, 1.78), a character string value (e.g. "abc", "this is fun"), or an unknown value ("?"). In all three cases, a cell has a logical value. This is because all known values other than 0 are interpreted as "true" by logical operators (e.g. AND, OR, NOT), and because the logical operators recognize three states: true, false, and unknown. Here are some examples. Expression Value ------------ ----- 1 and 0 = 0 1 and 1 = 1 1 and "abc" = 1 0 and 1.3 = 0 1 and ? = ? 0 and ? = 0 1 or 0 = 1 0 or 33.2 = 1 0 or "abc" = 1 1 or ? = 1 0 or ? = ? NodeBrain also has time expressions "~(...)" that evaluate to true or false at any given second in time based on the system clock. This is based on standard notions of a calendar and units or intervals of time, and a kind of algebra for manipulation of sets of "line" segments. We won’t go into it here, but the following examples illustrate the general idea. Expression True during (False otherwise) ----------------- ------------------------------------------- ~(mo,we) Monday and Tuesday ~(fr.d(1)) Fridays falling on the first day of a month ~(h(14).su) Hour 14 (14:00) on Sunday ~(h(8).fr.d(15)) Hour 8 (08:00) of Fridays falling on the 15th ~(mo[1]month) First Monday of a month ~(tu[-2]month) Second to last Tuesday of a month An "expert condition" is another form of cell expression that looks like a function call. You can think of it as a function call that executes whenever one of the argument cell expressions changes. # create expert with skills declared as "tree" define mystuff expert tree; define r1 on(x=40 and mystuff(a,b,c+7)) a=b+2; The way in which mystuff(a,b,c+7) is evaluated is determined by the skill "tree" associated with the mystuff expert. This skill is provided by a "skill module" (NodeBrain plug-in). Evaluation of an expert condition is just one of the methods that may be implemented by a skill module. |
|
A skill module implements one or more methods defined by the NodeBrain Expert Skill Module C API. Each line in the command examples below illustrates a reference to a different skill method. declare names module ./nb_mod_names.so;
declare nickname skill names.nick(...):... # initialize skill
define mynicks expert nickname("builtin"); # construct expert
assert mynicks("Ry","Ryan"),mynicks("Tay","Taylor"); # assert custom nicknames
define isnick cell mynicks(name); # expert condition
show mynick; # display knowledge associated with mynick
+mynicks(2,a+5); # expert command
We know from the syntax what method within the skill module is invoked in each reference to the expert "mynicks", but we would need documentation on the skill module names and its skill nick to know how the arguments are processed. We should point out that the arguments are cell expressions. |
|
An assertion is used to convey new information to an executing instance of the NodeBrain interpreter. (We sometimes refer to an executing instance of the NodeBrain interpreter as a "brain.") Simple assertions are like assignment statements with a cell name on the left and a cell expression on the right. assert x=a*b+c,y=a+b*c; When the value of a named cell changes as a result of the assertion, NodeBrain reacts to the change by re-evaluating cells that reference the modified cell. We say the cell "publishes" changes to the "subscriber" cells. When re-evaluation of subscriber cells changes their value, they in term publish their changes to subscriber cells. This can percolate all the way up the subscriber hierarchy as long as re-evaluation produces a change. define x cell a+b; define y cell a>b; # 1 if a greater than b, 0 otherwise define z cell x+y; define r on(z>20):-echo hello assert a=13,b=7; # this triggers rule r because z=21 assert a=12,b=8; # this causes re-evaluation of x and y (subscribers of a and b) assert a=2; # this causes re-evaluation of x, y, z, and r Notice the difference in our comments for the second and last assertions above? The reason the last assertion caused re-evaluation of z is because x and/or y changed. Then r was re-evaluated because z changed. Because assertions are a common in NodeBrain, as are assignments in other languages, NodeBrain has a shorthand notation using a back-tick to mean ASSERT. (We insist on a verb, or a symbol that represents a verb.) ‘x=a+b; assert x=a+b; We can assert values using "=" or definitions using "==". The following examples are similar, but not identical. define x cell a+b; # define x as a+b ‘x==a+b; # define x as a+b The DEFINE command in this example defines a new cell named x. The ASSERT command with "==" is the same if x is not already defined. If x is already defined, the DEFINED command will fail while the ASSERT command with redefine x. In the ASSERT command it is also possible for x to be in a parent context (explained later). ‘x==a+b; # define x ‘x==a*b; # redefine x define x cell a+b; # fails because x is already defined. An ALERT command is just like an ASSERT command, except it enables IF rules as you will see in the next section. alert a=13,b=7; # assert a=13 and b=7 with IF rules enabled. |
|
To respond to specific conditions or events, NodeBrain needs rules that tell it what to watch for and what action to take if the condition is true. define r1 on(a=b) x=2; define r2 if(a=b):-ps -ef | grep nb define r3 when(a=b):-echo hello An ON rule fires whenever the condition transitions from False or Unknown to True. define r1 on(a=b) x=2; assert a=7,b=7; # r1 fires assert a=2; # r1 transitions to False assert a=7; # r1 fires assert a=5,b=5; # r1 remains true and does not fire assert b=?; # r1 transitions to Unknown assert a=2,b=2; # r1 fires An IF rule fires when True after an ALERT command. Notice we didn’t say "transitions to True." It will fire on an ALERT even when conditions remains True. define r2 if(a=b):-ps -ef | grep nb assert a=7,b=7; # r2 does not fire because IF ignores ASSERT alert a=2,b=2; # r2 fires alert a=2,b=2; # r2 fires alert a=1,b=1; # r2 fires alert a=0,b=4; # r2 does not fire because the condition is false alert b=0; # r2 fires because the condition is true alert c=5; # r2 fires because the condition is still true The ON rule is used for state monitoring and responds to both the ASSERT and ALERT commands. It only responds to state changes. The IF rule is used for event monitoring and responds only to ALERT commands. (See COMMAND PREFIX section below for further restrictions.) It treats every ALERT command as an event, where the named cells are event attributes. An ALERT with the same parameters as the previous ALERT is recognized by the IF rule as a new event---even when none of the cells it monitors are referenced in the ALERT, as shown in the last line of the example above. The ON rule sees alerts as non-events when they don’t change the monitored state. The last rule we want to talk about here is the WHEN rule. It is identical to the ON rule, except it only fires one time and "undefines" itself. The WHEN rule applies equally to the ASSERT and ALERT commands, so it can be used for both state and event monitoring. There is also a thing called a "sequence rule." We are not going to talk about the details here but will show you what it looks like. It can appear as a command or a cell expression. The thing to know is that it looks like "{...}" and it monitors for a sequence of events, can change its own value, and can pass commands to the interpreter.
# this is a newer form of the WHEN rule
{on(a=7)‘b="abc";}
# this is like two WHEN rules that apply in sequence
{on(a=b)‘x=2;on(a>7)‘x=5;}
# this is a rule for changing the value of a cell
assert y=={=5;*{on(a=2);=4;on(a=5;=3}};
In the last example above, the value of y is initially 5. It then alternates between 4 and 3 as "a" transitions to 2 and 5 respectively. |
|
NodeBrain commands are interpreted within the context of a set of terms and rules called an "expert". A term may have a different meaning in a different context. In the following example we define an expert, "connie", and define three terms within the associated context. define connie expert; connie. define a cell 1; connie. define b cell a+5; connie. define hi on(a+b>3):-echo hello The context prefix "connie." (the period is important) on the DEFINE commands tells the interpreter how to interpret the commands. This same example, without the context prefix would look like this. define connie expert; define connie.a cell 1; define connie.b cell connie.a+5; define connie.hi on(connie.a+connie.b>3):-echo hello Referenced terms may be resolved at a higher level context if not defined in the target context. define connie expert; connie. define tex expert; connie. define a cell 1 connie.tex. define b cell a+5; # "a" is connie.a because there is no connie.tex.a # but "b" is connie.tex.b because we are defining it in connie.tex Undefined terms that are referenced in a cell expression are implicitly defined in the target context. define connie expert; connie. define b cell a+5; # "a" is implicitly defined The next example shows the equivalent explicit definition of "a". define connie expert; connie. define a cell ?; # connie.a is a cell with an unknown value connie. define b cell a+5; You can reference an undefined term in the target context when there is a defined term in a parent context. This is done by putting a period (".") in front of the term. define connie expert; connie. define tex expert; connie. define a cell 1 connie.tex. define b cell .a+5; # ".a" is connie.tex.a, not connie.a # The implicit definition is "define connie.txt.a cell ?;" An ALERT command only applies to IF rules defined in the target context. define connie expert; connie. define r if(a) x=2; alert a=1; # this does NOT cause connie.r to fire. alert connie.a=1; # this does NOT cause connie.r to fire. connie. alert a=1; # this DOES cause connie.r to fire. |
|
The SOURCE command is important to understand because it is used in one file to include commands from another like the source command in a shell script or an include in a C program. # include commands for myExtraRules.nb source myExtraFules.nb a=2,context="abc"; The parameters a=2 and context="abc" are available within myExtraRules.nb for controlling conditional processing and symbolic substitution. define %{context} expert;
%if(a>1);
%{context}. define r0 on(x>21):-mail fred@flintstone.com < myap.log
%endif;
%{context}. define r1 on(x=17) m=0;
|
|
See nb(1). NodeBrain prototype releases, those starting with a 0 like 0.6.0, should be used for experimental purposes only, unless you are able to verify their reliable for your application from your own testing. I use these releases in production applications, but makes no claim they will work as expected in your applications. But please experiment and report bugs by linking to the project page from the home page, http://www.nodebrain.org, or send email to <bugs@nodebrain.org>. |
|
Ed Trettevik <eat@nodebrain.org> |