Using a Control ShellTopAdd Another KSApplication Startup and Event FunctionsGoTo Top

Application Startup and Event Functions

In the last exercise, we needed to create the known-world space instance, with x and y dimensions, before we started the Agenda Shell. We also needed to call delete-blackboard-repository before calling start-control-shell to execute another run of our developing application. It is convenient to have these activities performed automatically whenever the control shell is started, so we'll do so in this exercise.


This exercise shows you how to:


Prerequisites

  (in-package :gbbopen-user)

  (define-unit-class location ()
    (x y)
    (:dimensional-values
      (x :point x)
      (y :point y))
    (:initial-space-instances (known-world)))

  (defmethod print-instance-slots ((location location) stream)
    (call-next-method)
    (when (and (slot-boundp location 'x)
               (slot-boundp location 'y))
      (format stream " (~s ~s)"
              (x-of location)
              (y-of location))))

  ;;; ====================================================================
  ;;;   Startup KS

  (defun startup-ks-function (ksa)
    (declare (ignore ksa))
    ;; Create an initial location unit instance at (0,0):
    (make-instance 'location :x 0 :y 0))

  (define-ks startup-ks
      :trigger-events ((control-shell-started-event))
      :execution-function 'startup-ks-function)

Step 1: Define an initialization function

Edit your tutorial-example.lisp file and add the following function definition at the end of the file:

  (defun initializations (event-name &key &allow-other-keys)
    (declare (ignore event-name))
    ;; Clean up any previous run:
    (delete-blackboard-repository)
    ;; Make a new known-world space instance:
    (make-space-instance 
     '(known-world)
     :dimensions '((x :ordered) (y :ordered))))

The first thing to note about the function definition is the argument signature: initializations is to be invoked with an event name (which is ignored in our function) and possibly other keyword arguments (indicated by the &key and &allow-other-keys lambda list keywords). This argument signature conforms to GBBopen's event-function capabilities, which will be introduced in the next step in this exercise.

When initializations executes, it deletes all of our application unit and space instances from the blackboard repository. Only ks, ksa-queue, and ordered-ksa-queue unit instances, which are defined by the control shell as retained, are not deleted by delete-blackboard-repository. Then initializations creates a new (known-world) space instance with ordered dimensions x and y.

Step 2: Add an event function

GBBopen allows you to attach functions, called event functions, that are called whenever a specific event is signaled. Each event function must accept the arguments associated with every event class to which it is added. In addition, the function should accept additional arguments that are associated with all subevents of the specified event classes. This is achieved by specifying &allow-other-keys in the lambda list of the function.

Here are GBBopen's defined event classes when the Agenda Shell has been loaded:

Event classes shown within rectangles are abstract event classes that cannot be signaled. Nevertheless, abstract event classes are very convenient if we wish to attach an event function to an entire subtree of event classes. We used abstract event classes to advantage earlier when we enabled display of all control-shell events by evaluating:

  gbbopen-user> (enable-event-printing '(control-shell-event :plus-subevents))
  nil
  gbbopen-user>
or the shorthand equivalent:
  gbbopen-user> (enable-event-printing '(control-shell-event +))
  nil
  gbbopen-user>

Add the following form at the end of your tutorial-example.lisp file:

  (add-event-function 'initializations 'control-shell-started-event
                      ;; Initializations should be done first!
                      :priority 100)
(We'll place the add-event-function form immediately after the initializations function definition in our file, but this choice of location is purely a code organizational style preference—the form could be placed anywhere relative to the function definition.)

Step 3: Run the application

Start a fresh Common Lisp session, compile and load the tutorial-example.lisp file directly from the editor buffer (using C-c C-k in SLIME; C-c C-b in ELI) and start the Agenda Shell again:

  gbbopen-user> (start-control-shell)
  ;; Control shell 1 started
  ;; No executable KSAs remain, exiting control shell
  ;; Control shell 1 exited: 3 cycles completed
  ;; Run time: 0 seconds
  ;; Elapsed time: 0 seconds
  :quiescence
  gbbopen-user>

Note that our developing application performs the same as it did in the last exercise, but now our initializations event function is taking care of all the details of starting up our application. We no longer have to remember to create the known-world space instance or to delete the blackboard repository before running the application another time.

Step 4: Run it Again

Let's verify that we can re-run our application. Without doing anything else, start the Agenda Shell again:

  gbbopen-user> (start-control-shell)
  ;; Control shell 1 started
  ;; No executable KSAs remain, exiting control shell
  ;; Control shell 1 exited: 3 cycles completed
  ;; Run time: 0 seconds
  ;; Elapsed time: 0 seconds
  :quiescence
  gbbopen-user>

As before, our initializations event function took care of all the details of starting up our application.

Step 5: It's a new world...

GBBopen allows us to restrict the classes of unit instances that can be stored on a space instance. For example, we can limit the known-world to location unit instances by specifying an :allowed-unit-classes value to make-space-instance:

  (defun initializations (event-name &key &allow-other-keys)
    (declare (ignore event-name))
    ;; Clean up any previous run:
    (delete-blackboard-repository)
    ;; Make a new known-world space instance:
    (make-space-instance 
     '(known-world)
     :allowed-unit-classes '(location)
     :dimensions '((x :ordered) (y :ordered))))
Attempting to add any unit-instance that is not a location to known-world will now generate an error.

It is often convenient to specify the dimensions of a space-instance relative to those of one or more unit classes. Edit the definition of initializations, removing the x and y dimensions specification:

  (defun initializations (event-name &key &allow-other-keys)
    (declare (ignore event-name))
    ;; Clean up any previous run:
    (delete-blackboard-repository)
    ;; Make a new known-world space instance:
    (make-space-instance 
     '(known-world)
     :allowed-unit-classes '(location)
     :dimensions '((x :ordered) (y :ordered))))
and replacing it with a call of dimensions-of to obtain the dimensions associated with instances of the location unit class:
  (defun initializations (event-name &key &allow-other-keys)
    (declare (ignore event-name))
    ;; Clean up any previous run:
    (delete-blackboard-repository)
    ;; Make a new known-world space instance:
    (make-space-instance 
     '(known-world)
     :allowed-unit-classes '(location)
     :dimensions (dimensions-of 'location)))

Step 6: Run the application again

Compile and load the tutorial-example.lisp file directly from the editor buffer (using C-c C-k in SLIME; C-c C-b in ELI) and start the Agenda Shell again:

  gbbopen-user> (start-control-shell)
  ;; Control shell 1 started
  ;; No executable KSAs remain, exiting control shell
  ;; Control shell 1 exited: 3 cycles completed
  ;; Run time: 0 seconds
  ;; Elapsed time: 0 seconds
  :quiescence
  gbbopen-user>

Verify the dimensionality of the known-world space instance by evaluating:

  gbbopen-user> (describe-space-instance '(known-world))
  Standard-space-instance #<standard-space-instance (known-world)>
    Allowed unit classes: t
    Dimensions:
      (x :ordered)
      (y :ordered)
  gbbopen-user>


The GBBopen Project


Using a Control ShellTopAdd Another KSApplication Startup and Event FunctionsGoTo Top