/*  ATNC.PL  */



:- reconsult( 'atncommon.pl' ).



/*
Introduction.
-------------

This file defines predicates that depend on the internal representation
of ATNs. ATNCOMMON.PL defines the representation-independent predicates.


Interface representation of ATNs (the 'expanded form').
-------------------------------------------------------

The interface between the two files is the representation of a node
and its body and arcs as a structure:
    atn( Node, Command, Arcs )
Here, Node is the original node term; Command is the original command,
as a Prolog goal ('true' if there was no command); and Arcs is a list of
the form
    [ Cond1, Node1, Cond2, Node2, ... CondN, NodeN ]
which defines the arcs. The conditions are Prolog goals: the final one
(CondN) is always 'true'. If the original ATN had no default arc, the final
one (NodeN) is 'failure'.             

So the definition
    count(N) ::
        Rem is (N mod 2)
        to odd(N) if Rem=0
        to even(N).
becomes
    atn( count(N), (Rem is (N mod 2)), [ Rem=0, odd(N), true, even(N) ] ).

Note that this representation is _not_ the same as the internal representation
used when interpreting ATNs.


Exported predicates.
--------------------

This file exports:
    do_node( Node )
    assert_expanded_atn( Expanded_ATN )
    retractall_expanded_atn( Node )

'do_node' is for the user. Call it with a node as argument to start executing
an ATN.

'assert_expanded_atn' and 'retractall_expanded_atn' are for the loading routines
in ATNCOMMON.PL.

'assert_expanded_atn' converts to internal form and asserts the ATN.

'retractall_expanded_atn' retracts all nodes matching its argument.


Internal representation of ATNs.
--------------------------------

In this file, ATNs are represented as clauses for the predicate '$node'.
'$node' has two arguments. The first is the name of the node to be
entered. The second will be instantiated to the next node.

Clauses contain a tail which obeys the command and selects the
next node. The clause for the node shown above would be

    '$node'( count(N), Next ) :-
        Rem is (N mod 2),
        ( Rem=0 -> Next = odd(N)
        ; Next = even(N)
        ).
*/



/*
The interpreter.
----------------

The main predicate is do_node( Node+ ). It starts executing an ATN at
Node, and fails or succeeds as defined in the documentation.
*/


do_node( failure ) :-
    !, fail.

do_node( success ) :- !.

do_node( A ) :-
    '$node'( A, Next ),
    !,
    do_node( Next ).



/*
Asserting and retracting nodes.
-------------------------------

This section includes the transformation to internal form by
'assert_expanded_atn'.

*/


retractall_expanded_atn( Node ) :-
    retractall( '$node'(Node,_) ).


assert_expanded_atn( atn(Node,Command,Arcs) ) :-
    atn_to_clause( Node, Command, Arcs, Clause ),
    assert( Clause ).


atn_to_clause( Node, Command, Arcs, Clause ) :-
    Clause = (Head :- Tail),
    Head = '$node'( Node, NextNode ),
    Tail = (Command , NextNodeGoal),
    arcs_to_if( Arcs, NextNode, NextNodeGoal ).


arcs_to_if( [], succeed, true ) :- !.

arcs_to_if( [true,Next|Rest], NextNode, Command ) :-
    !,
    Command = ( NextNode = Next ).

arcs_to_if( [Cond,Next|Rest], NextNode, Command ) :-
    Command = ( Cond -> (NextNode = Next) ; RestOfIf ),
    arcs_to_if( Rest, NextNode, RestOfIf ).
