494 lines
18 KiB

<TITLE>Galapagos - Scheme Extensions</TITLE>
<META NAME="GENERATOR" CONTENT="Mozilla/3.01Gold (Win95; I) [Netscape]">
<BODY background=stone.jpg>
<A href="background.html"><IMG border=0 src=prev.gif ALT=" [PREV] "></A>
<A href="gui.html"><IMG border=0 src=next.gif ALT=" [PREV] "></A>
<A href="index.html#toc"><IMG border=0 src=toc.gif ALT=" [PREV] "></A>
<HR width=80% align=right color=blue>
<LI><A HREF="extensions.html#THE NEW ENVIRONMENT">The New Environment Model</A></LI>
<LI><A HREF="extensions.html#THREADS">Threads</A></LI>
<LI><A HREF="extensions.html#CONSOLES">Consoles</A></LI>
<LI><A HREF="extensions.html#DRAWING">Drawing Boards</A></LI>
<LI><A HREF="extensions.html#TURTLES">Turtles</A></LI>
(Notifications) and Message handlers</A></LI>
<HR WIDTH="100%"></P>
<P>We have extended Scheme in two main
directions: Turtle graphics and multithreading:<BR>
<P>The <I>turtle</I> object lives on a board on which it can move and draw.
A turtle can also communicate with the board and &quot;see&quot; colors
or other turtles. Galapagos Scheme provides a set of primitives to create
and manage such turtles and the boards they live on. <BR>
<P>A set of additional primitives enable the programmer to create multiple
interpreters that run concurrently. The environment model was extended
to support shared or thread-specific environments, and primitives to handle
multiple environments were also added. <BR>
<P>A frame is a table which maps (or <I>binds</I>) names to values. An
environment is a chained list of frames in which the interpreter works.
<P>For example the command: </P>
<P><I>(define x 7)</I> </P>
<P>creates a binding between <I>x</I> and the value <I>7</I>. </P>
<P>A typical environment looks like this:</P>
<IMG border=0 SRC="Envs.gif" HEIGHT=125 WIDTH=459><BR>
Each rectangle denotes a frame and inside it are the bindings it holds.
The rightmost rectangle is the global environment.<BR>
<P>When a variable is evaluated, the interpreter first tries to find it
in the current frame. If a suitable binding can't be found, the interpreter
moves to the next frame in the environment and searched for a binding there.<BR>
<P>In our example if we write <I>x</I> in the command line we'll get <I>12</I>
as the answer because all such computations take place at the global environment.
<P>A function application is always evaluated with respect to the environment
the in which it was defined. (A function &quot;holds&quot; its environment,
hence the name &quot;closure&quot;) This means that if we write </P>
<P><I>(define (f) x) </I></P>
<P>and then </P>
<P><I>(f)</I> </P>
<P>the result will be </P>
<IMG border=0 SRC="Envs2.gif" HEIGHT=140 WIDTH=551><BR>
In traditional SCHEME we have only one interpreter running at a time, so
at a given point of calculation there is only one environment. In Galapagos
multiple interpreters can run at the same time, and each of them has its
own environment.<BR>
<P>Under Galapagos's environment model, every interpreter works on its
branch of an &quot;environments tree&quot;, but can also evaluate an expression
in any other environment in the tree. If two interpreters have a shared
node on the tree, then from that point up (towards the global environment)
all the bindings are the same for the two interpreters. The global environment
is shared by all interpreters. If an interpreter changes the value of some
variable, the binding is changed in all other interpreters that have access
to the frame where the variable was declared. Obviously, caution should
be taken when writing to a shared variable.<BR>
<P>As an example, if a user created two new threads, called A and B, and
then evaluated: </P>
<P><TT><FONT FACE="Courier New">First thread&gt;</FONT></TT> <I>(define
x 7)</I> </P>
<P><I>(define (f) ...)</I> </P>
<P><TT><FONT FACE="Courier New">Thread A&gt;</FONT></TT> <I>(define (g)
x)</I> </P>
<P><TT><FONT FACE="Courier New">Thread B&gt;</FONT></TT> <I>(define x 4)</I>
<P>this is how the environment model would look like:<BR>
<CENTER><P><IMG border=0 SRC="img00001.gif" HEIGHT=407 WIDTH=654><BR>
<P>Now consider what happens when the user evaluates this: </P>
<P><TT><FONT FACE="Courier New">Thread A&gt;</FONT></TT> <I>(set! f g)</I>
<CENTER><P><IMG border=0 SRC="img00002.gif" HEIGHT=431 WIDTH=692><BR>
<P>Now, evaluating <I>(f)</I> in thread B will call the function defined
in thread A. It will return 12 which is the value of x in f's environment.
If thread A defines a new x (using <B>define</B>), it will affect the result
of subsequent calls to f.<BR>
<P>Sharing environments and frames are Galapagos's way of allowing shared
data. By default, however, most calculations are done at thread-specific
frames. (More on this subject in the next section). Primitives are supplied
to explicitly reference and manage environments: <B>clone-environment</B>
can create a copy of an environment (so changing a binding in one copy
does not alter the other); <B>extend-environment</B> and <B>pop-environment</B>
can add and remove frames to and from environments. More environment functions
are found in the next section of this document.<BR>
<P>A thread is a SCHEME interpreter. The <I>base environment</I> of a thread
is the thread's topmost environment. All forms entered at the thread's
console or as arguments to <B>new-thread</B> are evaluated in the base
environment. In traditional SCHEME there is only one thread of execution.
It is a single thread and its base environment is the global environment.
In Galapagos many interpreters can run concurrently, and each have its
own environment (changing dynamically as computation progresses) and a
base environment (which can be explicitly changed).<BR>
<P>One thread is created by Galapagos upon startup. It is called the <I>main
thread</I>, and it lasts for the whole Galapagos session. Its base environment
is the global one - much like a traditional Scheme interpreter. Additional
threads can be created using <B>new-thread</B>. These have their base environment
set to a new environment, containing a single fresh frame pointing to the
global environment. Any calculation done at the new thread's console takes
place in this thread-local environment. However, if closure functions are
used, then their evaluation may take place at the global environment or
at some other thread's space, depending on where that function was defined.
<P>When a thread finishes the execution of its commands it terminates.
There are two exceptions to this rule: </P>
<LI>The main thread can be only terminated by using <B>quit-program</B>.
<LI>A thread that is bound to the console will not terminate at the end
of execution but will wait for the next command input. </LI>
<P>Threads can communicate using the predicate <B>tell-thread</B> or by
using the asynchronous message-queues system described later. In addition,
SCM's <B><I>arbiters</I></B> were improved to be multithread safe. An arbiter
object can serve as a guard on a critical section (where only one thread
can work at a given time) of the program. The relevant primitves are <B>make-arbiter</B>,<B>
try-arbiter</B>, and <B>release-arbiter</B>. <BR>
<P>Note: Galapagos supports Scheme's notation of <B><I>continuations</I></B>.
However, two restrictions apply: </P>
<LI>Only &quot;cheap&quot; continuations are supported. That is, a continuation
can only be called when it is still active. This allows for continuations
to be used to implement exception handling, etc. </LI>
<LI>Continuations can not cross thread boundaries. Also continuations,
like any other Scheme object, can be handled by any thread, they can only
be called from within the thread that created them. Trying to call a continuation
from a different thread will cause an error. </LI>
<P>A <I>console</I> is a text window where the user can type commands (when
the interpreter is idle) and see output. A console has a name which can
be changed dynamically, which appears on its title bar. A thread may or
may not be bound to a console. Information printed by a non-bound thread
is lost; a non-bound thread waiting for input is stuck (unless provisions
were made to allow a new console to be created by means of inter-thread
communications.) If a non-bound thread has nothing to do, instead of waiting
for input like a bound thread, it will terminate.<BR>
<P>The main thread is always bound to a console. To bind a thread to a
console use the command <B>bind-to-console</B> from within the thread.<BR>
<P>A board (window) is the graphical board on which the turtles and the
user draw. It is a bitmap on which the user can draw interactively, by
using the supplied GUI, or by creating turtles and instructing them to
do the drawings.<BR>
<P>The controls of the graphical user interface are located on the toolbar.
The &quot;shapes&quot; of drawing are either a rectangle, a line or free
hand drawing. The user pen can have three widths which are found under
the <B>User Pen</B> menu. The numbers next to the sizes are the widths
in pixels.<BR>
<P>The colors of the user pen can be changes either from the <B>User Pen
</B>menu or from the toolbar's color buttons. When choosing from a toolbar
button, the user can know exactly what color (in RGB format) is used. <BR>
<P>Each window has a name which is written on its title bar which can be
changed using the <B>rename-window!</B> command. The board can be cleaned
from all drawings using the <B>clear-window </B>command. <BR>
<P>Since the board is a bitmap it can be saved to a BMP file using the
<B>save-bitmap</B> command. A new background from a bitmap file can be
loaded using the <B>load-bitmap</B> command.<BR>
<P>A turtle is an object which is connected to a certain board. Each turtle
has a pen with which it can draw on that board. The user can change the
state of the turtle's pen including giving it the color of the board's
background color (using the <B>pen-erase! </B>command). The pen will draw
when it is &quot;down&quot; and will not draw when it is &quot;up&quot;.
Turtles can move between boards using the <B>move-turtle-to-window</B>
<P>Each turtle holds its location as the a pair of coordinates where 0,0
is the upper left corner of the board and 800,600 is the bottom-right corner
of the board. The turtle's location can be changed by giving the turtle
commands such as <B>forward!, backwards!, move-to!</B> or by using the
move button from the toolbar.<BR>
<P>A turtle also has a heading which is the direction it will move on the
<B>forward!</B> command. The heading is in degrees, 0 meaning upwards and
increasing clockwise, thus 90 means rightwards and so on. A turtle's heading
can be changed by commands such as <B>right!, left!, </B>and<B> set-heading!</B>
or interactively, by using the move button on the toolbar and pressing
the control key.<BR>
<P>A turtle can be visible on the board or be hidden. When it is visible
the user can decide if it wants a &quot;solid&quot; or &quot;hollow&quot;
turtle using the <B>make-hollow! </B>and <B>make-solid!</B> commands.<BR>
<P>A turtle is always connected to a certain board, which is the board
it is drawing on. To create a new turtle on a board use the <B>make-turtle</B>
or the <B>clone-turtle</B> commands. A new turtle (created with the <B>make-turtle</B>
command) will be black, solid, heading north and with it's pen down, in
the center of the board. A cloned turtle will have exactly the same inner
state as its parent.<BR>
<P>A turtle can also look at the board and see other turtles or colors.
By using the command <B>look</B> the user can tell the turtle the area
in which to look and what to look in this area. </P>
<P>Example: </P>
<P>The command </P>
<P><I>(look t 50 20 '(0 0 0))</I> </P>
<P>will cause the turtle <I>t</I> to look for black pixels in the area
in radius 50 from the turtle and 20 degrees to each side of the heading
line, shown here in blue: </P>
<CENTER><P><IMG border=0 SRC="img00003.gif" HEIGHT=75 WIDTH=48><BR>
<P>A turtle can have interrupts. Each interrupt is defined in terms of
turtle's vision. Whenever a turtle starts or stops seeing a given target,
a predefined message is sent to the thread which asked the interrupt. The
user can determine if the interrupt will notify on every change (like a
&quot;can see&quot;- &quot;can't see&quot; toggle) or only when one change
happens (only &quot;can see&quot; or &quot;can't see&quot; toggle). A message
can be any valid SCHEME object.<BR>
<P>Example: </P>
<P>The command </P>
<P><I>(turtle-notify t &quot;I-see&quot; &quot;I-don't-see&quot; 50 20
color-black)</I> </P>
<P>tells the turtle <I>t</I> that every time it sees the color black it
should send the message <I>&quot;I-see&quot;</I> and when it doesn't see
the color black any more it should send the message <I>&quot;I-don't-see&quot;</I>.
<P>Below is an example of what messages (or no message) <I>t </I>will send
while it is moving forward, encountering two black lines on its way:<BR>
<IMG border=0 SRC="vision.gif" HEIGHT=183 WIDTH=669></P>
If the interrupt was of kind &quot;can see&quot; (<B>notify-when</B> command)
only the <I>&quot;I-see&quot;</I> messages were sent, and if it was a the
&quot;can't see&quot; interrupt (<B>notify-when-not</B> command) only the
<I>&quot;I-can't-see&quot; </I>style messages were sent.<BR>
<P>A special &quot;user interrupt&quot; is invoked when the user right-clicks
the turtle or a window. The <B>notify-on-click</B> command is used to enable
<P>A thread can tell the turtle to delete a certain interrupt using the
<B>turtle-no-notify</B> command. It can also tell the turtle to disable
all interrupts using the <B>stop-notifying</B> command. <BR>
<P>In order to process the messages sent from a turtle's interrupt (or
from another thread, as presented later) the thread must install a <I>message
handler</I> which is a one argument function. If no handler is installed
the turtle's messages are lost. There can be only one handler per thread.
If the handler is installed then every time an interrupt is invoked, the
handler function in called with the message sent by the interrupt as its
argument. <BR>
<P>Example: </P>
<P>We declare the function: </P>
<P><I>(define (my-print x) (write x) (newline))</I> </P>
<P>and then install <I>my-print</I> as the current handler with: </P>
<P><I>(install-handler my-print)</I> </P>
<P>from now on every message a turtle's interrupt sends will be printed
on screen. If <I>my-print</I> was installed in the previous example then
we would have seen: <BR>
<P><I>&quot;I-see&quot;</I> </P>
<P><I>&quot;I-don't-see&quot;</I> </P>
<P>on the screen.<BR>
<P>A good example to view the interrupts in action is to make a turtle
turn each time it sees a color and then let it wander aimlessly. Then use
the user pen to draw lines the turtle's way and watch it change direction.
See the PINGPONG.SCM file for a demo program. <BR>
<P>The message-handler concept can be used as a mean of synchronous inter-thread
communications. The tell-thread functions sends a message to a thread,
which will be treated as an interrupt-generated message: It will cause
the thread's message handler function to be called with tell-thread's argument
as its own. This allows one thread to initiate a computation in a different
thread's environment and CPU space synchronously and without sharing environments.
<P>In order to let threads communicate between themselves asynchronously
a system of message queues was developed. A queue is an object which stores
and relieves messages, stored in FIFO (First In First Out) style, meaning
messages are read in the order of arrival to the queue. Supported messages
are pairs of type and body, both of which can be any valid SCHEME object.
Looking for messages of a certain type is also supported, allowing implementation
of more flexible communication schemes than plain FIFO.<BR>
<P>A thread can check if there are any messages in a given queue, if it
does <B>get-message</B> without checking first if there are messages in
the queue it will wait a given time-out or forever if no time-out is given.
If by the end of the time-out no message were in the queue the result will
be false.<BR>
<P>Example: </P>
<P>In this example a queue <I>q</I> is created then a message is posted
into the queue and read from it.<BR>
<P><I>(define q (make-queue))</I> </P>
<P><I>(post-message q (cons 'type-circus 'bozo-the-clown))</I> </P>
<P><I>(define msg (get-message q))</I><BR>
<P>now the command </P>
<P><I>(car msg) </I></P>
<P>will give </P>
<P><I>type-circus</I> </P>
<P>and the command </P>
<P><I>(cdr msg) </I></P>
<P>will yield </P>
<P><I>bozo-the-clown</I>. </P>
<HR width=80% align=left color=blue>
<A href="#top"><IMG border=0 src=back.gif ALT=" [TOP] "></A>
<A href="background.html"><IMG border=0 src=prev.gif ALT=" [PREV] "></A>
<A href="gui.html"><IMG border=0 src=next.gif ALT=" [PREV] "></A>
<A href="index.html#toc"><IMG border=0 src=toc.gif ALT=" [PREV] "></A>