HELP EXEC                                    Jocelyn Paine November 1992


This module provides facilities for writing ``brains'' for Eden that, as
far as they are concerned, run continuously, rather than starting afresh
on each call to 'think'. In effect, it provides a simple form of
coroutine. Experienced Poplog programmers will see that it is an simple
interface to LIB PROCESS (see HELP PROCESS): I have written it so that
novices can write co-routine style brains without having to know
anything more about LIB PROCESS, or how to call it from Prolog.

You can load it by doing
    library(exec).


Introduction
------------

Here's an example, which you can try by running EXEC_BUG.PL.

    :- library(exec).

    start_thinking :-
        goal_to_process( brain, Co ),
        asserta( co(Co) ).

    think( Action ) :-
        co( Co ),
        restart_process( Co, Action ).

    brain :-
        smell( here ),
        !,
        exec( grab ),
        exec( use ),
        brain.

    brain :-
        smell( S ),
        exec( S ),
        brain.

    bugdead( _, rerun ) :-
        start_thinking.

This is a bug which heads towards the food until in the same square,
same square, then grabs it, and then uses it. In doing this, it's like
the bug in VERY_SIMPLE_BUG.PL. However, it uses processes, and so
demonstrates the use of EXEC.PL.

The ``brain'' predicate is -brain-. You can see that it runs
continuously in a recursive loop, and calls -exec- everytime it decides
to obey an action. This is quite unlike the brain in VERY_SIMPLE_BUG.PL,
which starts afresh on each call to -think-.

Let's look at the code in more detail.
Example:
    brain :-
        smell( here ),
        !,
        exec( grab ),
        exec( use ),
        brain.

    brain :-
        smell( S ),
        exec( S ),
        brain.

If smell is not 'here' then it will be a direction. These directions
have the same name as actions, and so obeying them will cause the bug to
move nearer to the food, or at least to face towards it. This is how
VERY_SIMPLE_BUG.PL works too.

If smell is 'here', then the bug can grab the food. Now, once it's
done that, it can safely use it on the next action. So it's nice to be
able to write
    exec( grab),
    exec( use )
These two actions are separated by one simulation cycle. But by using
-exec-, we can ignore that, and pretend that one occurs immediately
following the other. The first -exec- returns control to the call of
-restart_process-, which was called from -think-. This returns to the
simulator, which finishes the cycle, starts the next one, calls -think-,
and re-starts -brain-. And so we get to the second -exec-. Incidentally,
this idea can be used in many other contexts than Eden, and coroutines
are a wonderful tool for structuring difficult programs. See HELP
PROCESS for more info. Of course, they will prevent your Prolog from
being portable.

Eden, of course, still expects its brain to be called -think-. So how do
we interface -brain- to -think-? The answer is, via the code in
-start_thinking-. This makes -brain- into a process or coroutine
by calling
    goal_to_process( brain, Co )                        

This process is held in the assertion
    coroutine( Co ).
Each time -think- is called, it restarts Co by calling
    restart_process( Co, Action )
which causes -brain- to run until it calls -exec- to return an
action.

Even if you're not sure what exactly is going on, you can imitate this
pattern for more complex brains. Just replace the code inside -brain- by
your own code. You don't need to have the entire brain in one predicate:
you can call -exec- from subpredicates, as in this rather contrived
example.

    brain :-
        smell( here ),
        !,
        grab_it,
        eat_it,
        brain.

    brain :-
        move_to_it,
        brain.

    eat_it :-
        exec( use ).

    grab_it :-
        exec( grab ).

    move_to_it :-
        smell( S ),
        exec( S ).


Reincarnation and -bugdead-
---------------------------

If you intend your bug to reincarnate, it's important to know how to
reset its brain. The point is that, once it's eaten the food in the
example above, the procedure -brain- has been ``used up''. You somehow
need to set it back to the start before it can be used again.

This is done via the code in -bugdead-. This calls -start_thinking-
before returning a result. This ensures that on reincarnation, -co-
contains a new brain process which, once again, would run from the
beginning.


Exported routines
-----------------

PUBLIC goal_to_process( proc ):

Converts -proc- into a process, returned as the result.


PUBLIC restart_process( co ):

Runs -co- until it calls -exec(action)-. -action- is then returned as
the result of -restart_process-, and -co- suspends itself, as described
above. -co- can either be a process which has not been run before, or
one which has, and is suspended.


PUBLIC exec( action ):

Called from inside -proc- to suspend and return an action.
