.. $Id: bc_rule.txt a2119c07028f 2008-10-27 mtnyogi $
.. 
.. Copyright © 2007-2008 Bruce Frederiksen
.. 
.. Permission is hereby granted, free of charge, to any person obtaining a copy
.. of this software and associated documentation files (the "Software"), to deal
.. in the Software without restriction, including without limitation the rights
.. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
.. copies of the Software, and to permit persons to whom the Software is
.. furnished to do so, subject to the following conditions:
.. 
.. The above copyright notice and this permission notice shall be included in
.. all copies or substantial portions of the Software.
.. 
.. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
.. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
.. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
.. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
.. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
.. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
.. THE SOFTWARE.

restindex
    crumb: Bc_rule
    page-description:
        The syntax of a backward-chaining rule.
    /description
    format: rest
    encoding: utf8
    output-encoding: utf8
    include: yes
    initialheaderlevel: 2
/restindex

uservalues
    filedate: $Id: bc_rule.txt a2119c07028f 2008-10-27 mtnyogi $
/uservalues

=============================================
Bc_rule Syntax
=============================================

Bc_rule
==========

Backward-chaining_ rules_ have four parts:

#. A unique name.
#. A `use clause`_.
#. An optional `when clause`_.
#. An optional `with clause`_.

::

    bc_rule ::= IDENTIFIER NL INDENT
                    use
                    [when]
                    [with]
                DEINDENT

The ``IDENTIFIER`` is the unique name for this rule_ and is used as the
corresponding Python function name in the generated <rb_name>_bc.py file
and also for the Python function name of the plan_ function (if any)
associated with the rule.  This name will show up in stack traces
associated with exceptions raised during inferencing or plan execution.

Use Clause
============

The ``use`` clause is the **then** part of the rule.  It identifies the
*goal* that this rule is prepared to prove.

::

    use ::= 'use' IDENTIFIER '(' {pattern,} ')' ['taking' '(' <python_arg_spec> ')'] NL
          | 'use' IDENTIFIER '(' {pattern,} ')' NL
             INDENT 'taking' '(' <python_arg_spec> ')' NL
             DEINDENT

Notice that it uses a single ``IDENTIFIER``.  The `rule base`_ name is implied
as the `rule base category`_ name (the name of the root rule base, see
`extending clause`_) for the rule base containing this rule.

Taking Clause
----------------

The ``use`` clause also defines parameters to the plan_ function (if one is
used for this rule_) with the optional ``taking`` sub-clause.

The *python_arg_spec* is not parsed by Pyke, but simply copied to the
output plan function.  Do **not** use ``$`` with these parameter names (or
their default values).

When Clause
==============

The ``when`` clause is the **if** part of the rule_.  It defines the
premises that must be true for this rule to succeed.

If the ``when`` clause is omitted, the only
requirement for the rule to succeed is that the ``use`` clause
`pattern matches`_ the goal.

If the ``when`` clause is specified, the rule succeeds for each combination
of true premises (see backtracking_).

::

    when ::= 'when' NL INDENT
                 {bc_premise NL}
             DEINDENT

    bc_premise ::= ['!'] [ name '.' ] name '(' {pattern,} ')' [ plan_spec ]
                 | compound_premise
                 | python_premise

    name ::= IDENTIFIER
           | '$'IDENTIFIER

Here are the links to the definitions for pattern_, compound_premise_ and
python_premise_.

If the *bc_premise* includes the ``!``, an AssertionError will be raised if the
premise fails on the first try.  This can help in debugging.

.. Note::
   This does not apply when the premise fails on backtracking_ (in which case
   it has already succeeded at least once).

If a single *name* is used in the *bc_premise*,
the `rule base category`_ for the current `rule base`_ (the root rule base
name, see `extending clause`_) is assumed.

If two *names* are used in the *bc_premise*, the first may name a rule
base category or some other `knowledge base`_.

If a rule base category name is used (or assumed), the currently active_
`rule base`_ for that category is used to prove the premise.

.. note::

   If the rule base category name is omitted, and therefore assumed
   to be the current rule base's rule base category, the current rule base
   does *not* have to be the active rule base for that category.  It could be
   the case that a derived rule base is the active rule base.  In that case,
   the derived rule base is used to prove the premise.

   In this way, different rules may be used to prove the same premise,
   depending upon which rule base has been activated.

Plan_spec
------------

A *plan_spec* is required for each premise that returns a subordinate plan_.
This shows what should be done with that subordinate plan_ function.

Thus, a rule's plan function is composed first of the collected
python_statements taken from its plan_specs (as described below), followed by
the python_statements within its `with clause`_ (if any).  The inclusion of
any plan_spec containing a python_statement will cause a plan_ function to be
generated for this rule, even if the rule lacks a ``with`` clause.

::

    plan_spec ::= [ 'step' NUMBER ] NL INDENT
                      {<python_statement> NL}
                  DEINDENT
                | 'as' '$'IDENTIFIER NL

Within each python_statement, the subordinate plan function is indicated by
``$$``.  The result of this function may be assigned to a Python variable,
but not a `pattern variable`_ (``$variable``).
Parameters from the rule's ``taking`` clause may be passed on to the
subordinate plan_ functions.

When multiple premises have python_statements in their *plan_specs*, the
python_statements in plan_specs *without* a ``step`` clause are executed first
in the order that they appear in the ``when`` clause.

Then the python_statements in plan_specs *with* a ``step`` clause are
executed in ascending NUMBER sequence.  It is permissible for the NUMBER
to be negative or a float.

If the ``as`` clause is used, the plan function is bound to the
pattern variable as a Python function, but not automatically executed.
This allows you to call the function (or not) when and as many times as you
please.  The parameters required are defined in the ``taking`` clause of the
rule used to prove the premise.

.. note::

   Within a forall_ or notany_ premise, the only ``plan_spec`` that may be
   used is the ``as`` clause.

With Clause
==============

The ``with`` clause contains Python statements to include in the plan_
produced by this rule_.  These Python statements may include
`pattern variables`_ whose values will be cooked_ into these statements
when the plan is created.

::

    with ::= 'with' NL INDENT
                 {<python_statement> NL}
             DEINDENT

The *python_statements* are included in the rule's plan function after
all of the calls to the subordinate plan functions made from the
*plan_specs* in the `when clause`_.

If the ``with`` clause is omitted, but the ``when`` clause has *plan_specs*
(excluding the *as* clause), a plan function is still generated for this
rule so that the subordinate plan functions are still called.

The *python_statements* are not parsed.  They are simply scanned for ``$``
pattern variables that don't occur within string literals or comments.
The values bound to these variables are cooked_ into the code to produce the
plan.

Thus, all pattern variables used within *python_statements* (both in the
``plan_specs`` and the ``when`` clause) must be bound to a value.  This
value is a constant value that never changes for this plan_.

.. note::

   This occurs after the entire top-level goal is proven so that it is
   permissible to bind these pattern variables to values *following* the
   execution of the rule containing them.


