[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: select-item-from-list

  Presently, I am leading a team of five programmers in a major
rewrite of a Pascal Programming environment.  Only one of them
had prior lisp experience, none of them had any MACL experience.

I generated the following messages to them to desribe a-lists
and to describe the use of the table-dialog-function.   Please
note that I desribe a-lists in a rather simplistic manner.  That
is not as important for your purposes as the example code that
shows how to use the table-print-function.

  -- Luke

  (After always asking for help, it feels really good to provide
   an answer!)

The purpose of this mail is to describe an alist, how it is used,
why it is needed, and how it has been used in the GPCeditor.  More
importantly, the purpose of this mail is to show how MACL 1.3.2
provides some functionality that makes the pervasive use of a-lists
in the GPCeditor unnecessary in SODA.

  This mail is particularly relevent to
  Brad: in the display of *plandraw-shape* objects in the window.
        You may want to switch to the new code in this mail.

  Blake: In the library, for the displaying of Pascal plans to the

  Randy: In the Design log, for the displaying of student-crumb

  Steve and Paul:  You will probably not use the dialog-item
                   information of this mail, but you should read
                   about a-lists.  They are an important lisp tool.

Association Lists:

Everything in lisp is an atom or a list.  Great.  So, what if we want
to associate a key with a value?  Then we use an a-list. Here is the
"official" definition:

  An a-list is a list of pairs where each pair is an association. The
  car of the pair is calle the key and the cdr is called the datum.

A lists are used extensively in the current GPCeditor.  For example,
in the Goal-Plan Bucket an a-list is used to manage the selection of
goals that are displayed in the Goal Bucket.

Specifically, we associate the name of the goal with the goal object
itself and store this in an alist.  An axample of this looks like this:

((G:GetString".#<Object 34, a *goal*) ("G:Next Goal".#<Object 42, a *goal*))

Thus, if we say:

(setf test-list
  '((G:GetString".#<Object 34, a *goal*) ("G:Next Goal".#<Object 42, a *goal*)))
and say:

(car test-list)

we get:

(G:GetString".#<Object 34, a *goal*)

In general, whenever there is a sequence-dialog-item used to display
information such as that above we use an a-list.  We use a-lists
because we can build the above representation fairly easily.

But, because of MACL 1.3.2, there is a MUCH better way of doing this.

The NEW Better way of doing this!

Lets say we have a sample object, called a *nameobj*.  Here is the

(defobject *nameobj*)

(defobfun (exist *nameobj*) (init-list)
  (have 'name (getf init-list :name "sample"))
   (init-list-default init-list)))

As you can see, this object does nothing more than create an object with
a single slot that contains a string.  Here is an example of how to use

? (setf test-obj (oneof *nameobj* :name "Luke"))
#<Object #957, a *nameobj*>
? (ask test-obj name)

Now, let's say we wanted to show this object in a *sequence-dialog-item*
in a small window.  Here is some code that creates a *dialog* window
with one item:

(oneof *dialog*
       :window-type :document :window-title "sample dialog"
       :window-position #@(364 127)
       :window-size #@(300 150)
       (list (oneof *sequence-dialog-item*
                    :dialog-item-position #@(17 18)
                    :dialog-item-size #@(156 48)
                    :dialog-item-text "Sample"
                    :cell-size #@(200 16)
                    :table-hscrollp nil
                    :table-print-function 'print-nameobj
                    :table-vscrollp t
                     (oneof *nameobj* :name "randy")
                     (oneof *nameobj* :name "brad")
                     (oneof *nameobj* :name "luke")))))

You should execute the above code.  As you can see, the dialog items
display in a "funky" way: they are displayed using the normal printed
representation of the object.  In other words, lisp always returns the
princ representation of a symbol when that symbol is entered.  Numbers
evaluate to themselves, and a *nameobj* will evaluate to this:

? 12
? test-obj
#<Object #957, a *nameobj*>

Thus, in the above dialog, MACL is using the princ function (the
default function) to display the items in the sequence.  We need to
change this and tell MACL to use a different function.

The new MACL 1.3.2 *table-dialog-item* defines a new slot in
the actual definition of the *table-dialog-item* object:


This function is defined by us and takes two arguments, the first
being the contents of the cell and the second bring a print stream.
Now, what we want to do is defined the above dialog such that the
names of the objects are displayed, not the objects themselves.
So, we add the following function:

(defun print-nameobj (a-nameobj a-stream)
  (declare (object-variable name))
  (format a-stream "~a" (ask a-nameobj name)))

and then redefine the *dialog* as follows:

(oneof *dialog*
       :window-type :document :window-title "sample dialog"
       :window-position #@(364 127)
       :window-size #@(300 150)
       (list (oneof *sequence-dialog-item*
                    :dialog-item-position #@(17 18)
                    :dialog-item-size #@(156 48)
                    :dialog-item-text "Sample"
                    :dialog-item-nick-name 'nameobj-list
                    :cell-size #@(200 16)
                    :table-hscrollp nil

                    :table-print-function 'print-nameobj

                    :table-vscrollp t
                     (oneof *nameobj* :name "randy")
                     (oneof *nameobj* :name "brad")
                     (oneof *nameobj* :name "luke")))))

This definition tells MACL to call the function print-nameobj whenever
the contents of a cell in the table is to be redrawn.

This is pretty important to understand, and you should all see how this
code makes it pretty easy to use *sequence-dialog-items*.  So, take
some time out and play around with these code chunks. Consider how
this method of displaying objects will change how we display goals in
the GPCeditor:

  1. Instead of an a-list of ("Goal Name".#<goal object>) I now have
     a simple list of goal objects: (#<goal object> #<goal object>)

     As you migh guess, building and maintaining such a list is MUCH
     faster than building and maintaining an a-list.

  2. When the user selects a cell in the table, I don't have to access
     anything or write any functions to get at the *goal* object!  It
     is only the default function that MACL calls for printing the
     object that we have modified: the actual object itself, in the
     list, is not modified.

Note that this applies to the displaying of *crumb-objects* in the
Design Log, the displaying of Pascal Langauge Plans in the library,
the display of plandraw-shape objects in Plandraw, the display of
data objects in the Data Objects Workspace, ....


a-lists are a very important concept, and they will continue to be used
in the GPCeditor.  For example, a global variable containing all the
library categories and the plans that are members of those categories
could be stored in an a-list, with the key of a pair in the list being the
category name and the cdr of the pair being a list of all plans.

(Blake - I use the library category as an example - I know you will
 probably implement this differently.)

Note each of us except Paul and Steve will be using the code in this
example to make our lives a lot easier.  In the process of finishing the
port to MACL 1.3.2 I am finding this type of representation very easy
to work with.

Try the examples in this mail, send any questions.

 -- Luke