Back to index

LispMe sample programs

The sample programs are included as a MemoPad import file samples.csv which can be installed all at once this way. Alternatively, use the Source code hyper link given at each sample.

Utilities

; Built-ins [removed]

This memo is obsolete due to LispMe's new handling of builtins.

; Standard library

Source code

All procedures listed in the Catalog under Category Library procedure are defined in this memo. You should have this memo loaded most of the time, unless you're running into memory troubles.

; Utility library

Source code

Some useful (non-standard) functions

; Graphic utilities

Source code

Defines some procedures to modify the graphics state variables and some other useful procedures and variables.

Just use the GUI controls menu command when graphic output has trashed LispMe's main dialog to redraw it.

; HanDBase utilities

Source code

Defines hb-getrecord which reads an entire record from a HanDBase database and converts all fields from HanDBase's internal string representation to a more appropriate one depending on the fields internal type. A record is represented as a list.

Additionally, all linked records are read recursively and embedded as a list of records in the owner record.

Note that the date and time parsing functions use the German format (dd.mm.yy and hh:mm)

The function hb-getrecord is curried, so that repeated calls to the same DB can avoid re-reading the catalog (field descriptions). Use it like this:

  (let ((reader (hb-getrecord "MyDB")))
    (do looping conditions
      ... (reader recnum) ... ))

Small examples

; Ackermann

Source code

The classic non-primitive recursive Ackermann function. Don't try to evaluate (a 4 4) before buying an universe full of AAA cells!

; Towers of Hanoi

Source code

Another classic: List the moves necessary to move n disks from peg a to peg b using the auxiliary peg c in the game Towers of Hanoi.

(hanoi 3 'from 'to 'aux)

evaluates to

((from . to) (from . aux) (to . aux) (from . to) (aux . from) (aux . to) (from . to))

; even/odd mutual recursion

Source code

A stupid way to implement those, sure, but it demonstrates 3 things:

  1. mutual recursion in general
  2. try entering these definitions in the input field (don't load this memo before) and you'll get an error regarding undefined names. See here for an explanation. A solution is to enclose both definitions in a begin expression as described at define.
  3. even calling (odd 100000) will not exhaust heap or stack space proving that LispMe handles tail calls properly.

; count change

Source code

This memo was used in the following performance test. The call (cc 100 coins) (How many ways are there to change 100$ into 1, 2, 5, 10, 20, 50 dollar bills) was run on a variety of Scheme implementations:

LispMe was originally developed with Visual Age C++ by IBM on a Pentium 133 with 64 MB running OS/2 Warp. Recently I discovered that MIT Scheme 7.4 is available for OS/2 and was compiled with the same compiler, so I ran a simple performance test.

Performance measurement
MachineOS versionLanguageoperation mode runtime
Pentium 133OS/2 WarpMIT Scheme 7.4interpreted 7.00 s
Pentium 133OS/2 WarpMIT Scheme 7.4compiled to native 386 code 0.96 s
Pentium 133OS/2 WarpLispMe 1.2compiled SECD code 4.59 s
Pilot 1000PalmOS 1.06LispMe 1.2compiled SECD code 747.13 s
Pilot 1000PalmOS 2.02LispMe 1.4compiled SECD code 626.87 s
Pilot 1000PalmOS 2.02LispMe 1.6compiled SECD code 657.35 s
Pilot 1000PalmOS 2.02LispMe 1.7compiled SECD code 666.31 s
Pilot 1000PalmOS 2.02LispMe 2.0compiled SECD code 697.45 s
Palm IIIPalmOS 3.0LispMe 2.3compiled SECD code 662.45 s
Palm IIIPalmOS 3.0LispMe 2.7compiled SECD code 688.22 s
Palm IIIcPalmOS 3.5LispMe 2.7compiled SECD code 454.28 s
Palm IIIPalmOS 3.3LispMe 2.8compiled SECD code 583.93 s
Palm IIIcPalmOS 3.5LispMe 2.8compiled SECD code 384.27 s
Palm IIIcPalmOS 3.5LispMe 3.0compiled SECD code 417.13 s
Palm IIIcPalmOS 3.5LispMe 3.2compiled SECD code 403.23 s
Palm Tungsten T3PalmOS 5.2LispMe 3.2compiled SECD code 82.31 s
Pilot 1000PalmOS 2.02PocketC 0.98aunknown 1927.85 s

Considering the immense effort that went into MIT Scheme and the difference between a Pentium and a Dragonball, this result is not too bad, I think! Notice the performance increase in V1.4 (The decrease in later versions is due to run-time type checking the additional data types)

Note that some hacks which patch the system event handler may cause a significant slowdown!

This benchmark has been adapted for PocketC (Source code) to allow a comparison.

; Graphics demo

B/W graphics sample Color graphics sample Source code

Load ; Graphic utilities and just evaluate (demo). Compare the source with the output and note how to draw circles. See also how to access resources and draw bitmaps. In this case, resource 11000 of type Tbmp (=bitmap) is loaded and drawn. This bitmap (residing in a system resource) is the taxi image of a well-known Pilot easter egg!

Please note that both images were created by the same code proving the backward compatibility of the graphic system.

; Infinite streams

Source code

These definitions illustrate how to used delay to build infinite streams, try these expressions:

; Little schemer 19

Source code

This sample is from chapter 19 of The Seasoned Schemer, pages 165-175. It demonstrates, how continuations can be used to model coroutines. In this case, the function waddle traverses a tree, yielding control whenever it finds a leaf. The functions get-first and get-next provide a functional interface for waddle, which is used by two-in-a-row*?

The helper functions haven't been localized into the main function (like on page 176) to be able to play around with them.


More complete examples

; Function plotter

Sample plot Source code

Load ; Graphic utilities before. To plot a function, evaluate (plot function x-min x-may y-min ymax).

As the Pilot ROM routines have some glitches with clipping, you may notice spurious lines when the functions leaves the range [y-min..y-max]. Try to avoid this.

Feel free to enhance this plotter (it's only a demo!) and please send me a copy of your code in this case.

; Animated 3D graphics :-)

Source code

Evaluate (cube 80 30 30 12 35). OK, it's not Quake, but the animation runs at about 12 FPS. The short pauses indicate garbage collections. The parameters are

  1. x coord of center of top square
  2. y coord of center of top square
  3. x radius of ellipsis point travel along
  4. y radius of ellipsis point travel along
  5. height of cube

; Symbolic derivation

Derivation sample Source code

The function diff computes the symbolic derivation of a function entered in LispMe syntax. The result is somewhat simplified (e.g. (* (+ a 5) 1) => (+ a 5))

Try these steps:

(diff '(* (* x x) (* y x))) evaluates to (+ (* (* x x) y) (* (+ x x) (* y x)))

Now (diff it) evaluates to (+ (* (+ x x) y) (+ (* (+ x x) y) (* 2 (* y x))))

And again, (diff it) evaluates to (+ (* 2 y) (+ (* 2 y) (* 2 y)))

Finally, (diff it) evaluates to 0

Note: This sample has been changed in version 2.2 to show local defines, case and quasiquote.

; Tic-Tac-Toe

TicTacToe Demo Source code

You must load ; Standard library, ; Utility library, and ; Graphic utilities before. To play a game of Tic Tac Toe, just evaluate (ttt who algo).

who can be #t, meaning you have the first move, or #f to let Pilot begin the game.

algo selects the algorithm by which the Pilot selects its move:

To make your move, simply tap onto the square you want to mark. Tapping outside the game board aborts the game.

How Tic-Tac-Toe works

The board is represented as a list of 9 integers where each integer represents a square. 0 means an empty square, -1 means occupied by Pilot (X) and 1 means occupied by you (O). The board is numbered in this fashion:
012
345
678
A move is represented by a single number indicating the square to be occupied. The function eval returns a static evaluation of a board position: extend (curried) takes a position and returns a list of triples consisting of the new position, the move taken and the value of the new position for all possible moves (determined by poss-moves).

do-move returns the modified position when executing a move. find finds the best element of a list according to a predicate (which is assumed to be transitive)

So, static uses find to extract the best (lowest static value according to eval) triple from the list returned by extend and returns its move component.

smart filters the list before for positions, which are an immediate loss for Pilot. These positions are identified by not-loose, which uses extend in turn, this time with the player's moves.

human just waits for the player to tap a square and returns the new position, while pilot executes the move determined by its algo parameter for the Pilot. Finally, ttt is the game driver, calling human and pilot alternatingly, after setting up the result continuation which is called to end a game.

You way want to improve the Pilot's move algorithms (smart is quite slow, it always builds a search tree two levels deep) or implement real alpha-beta search. If you reach the MemoPad limit of 4k for the source, just split it into two memos and load both of them.

; Unify.lisp

; theory.lisp

Source code (unify)

Source code (theory)

This is a sample program sent by Winton Davies. He wrote:

OK, so here's a small LispMe Theorem Prover for the Palm Pilot OS2.0 . I ported it from a Lisp version that comes with Mac Common Lisp 4.1 ("mcl:user contributed code:AI/Expert Systems:AI:"(prove-all.lisp and unify.lisp). Feel free to correct any bits of scheme I didn't do correctly.

I believe the originating author is Mike Pazzani, from an Introductory AI course taught at UCI. However, it could also have been Rich and Knight or Touretsky (both books being referred to in the lecture notes). Perhaps Mike might fill us in?

It's probably a sub optimal port :) But it works on the test case. But I also have doubts as to its completeness. I'm not even sure how best to characterize it. The unify component works -- but doesn't do skolemization on functions it appears. The input has to be horn clause. The search method I haven't analysed... and applying the substitutions appears order dependent. Still, as I said -- it fits in 4K limit of memo-pad, and does work on the test case :-).

I don't know how you want to deliver them, but assuming Mike has no problems with them being public, then I have no problems either. The first file is called unify.lisp (contains unify and prove-all), the second is the dinky example...

Load the ; Standard library before and evaluate (test) to see, who'll be eaten :-)

; Tracer

Source code

This memo provides a tracing facility for arbitrary LispMe procedures. To start tracing of any (top-level) procedure, invoke (trace procname) and to stop tracing invoke (untrace procname). These macros install and remove a tracing prologue/epilogue for the procedures which prints its parameters and return value together with the call nesting depth to a memo Trace in the Unfiled category.

The currently traced procedures are stored in the global list *tracing* as pairs consisting of the name and the original closure. Note the use of old-depth to store the nesting depth in the dynamic context before calling the traced procedure, so that multiple returns via continuations use the correct value. Just incrementing depth before the call and decrementing it afterwards wouldn't work in this case!

; tcp/ip samples

Source code

This memo provides two example functions to retrieve data from the Internet. The first (atomic-time) retrieves the current time and date from the atomic clock in Braunschweig, Germany.

The second example rate uses the FXP protocol for retrieving currency exchange rates. The page describing the protocol seems to have vanished, but this page shows some scripts using it.

Use international currency codes to request current exchange rates:

 (rate 'eur 'usd) => 0.8779 
as of 24. Nov 2001.

User interface examples

All 4 demos need the resource file GUIdemo.prc installed on your Pilot. To create or modify resource files, there are several methods. For each demos I used a separate resource script (*.rcp included in the gui subdirectory) to be compiled using PilRC but 'linked' all resources together into a single resource DB GUIdemo.prc.

; GUI demo

GUI Demo LispMe source code

PilRC source code

Totally useless, but shows almost all UI elements supported. Have a look at the event handling in the subdialog invoked by pressing the Scroll button. There is a generic event handler synchronizing an entry field and its scrollbar. The higher-order function scroll-handler creates an event handler from the field and the scrollbar id.

Another higher-order function chain executes an arbitrary number of event handlers until the first returns #t (which indicates that the event has been completely handled).

The continuous display of the current ticks value is done by specifying a timeout in the event loop and redrawing it on each timeout event.

; Form navigation

LispMe source code

PilRC source code

Shows navigation between forms using frm-goto, frm-popup and frm-return.

; Doodle

Doodle Demo LispMe source code

PilRC source code

The most basic drawing program in 10 lines of code.


; Calculator

Calculator Demo LispMe source code

PilRC source code

Simple 4 function calculator.


; IR Chat

IR Chat Demo LispMe source code

PilRC source code

This sample shows connecting two Palms via infrared. Both Palms must have LispMe and this memo installed. Start the demo on both Palms and press the Connect buttons on each. Now you can send and receive text messages.

This demo uses the Palm's virtual serial IRComm port which can be accessed as a standard serial device. Sending data is simply done with write. To receive data, timeout events are enabled (one per second) and the serial port is polled using a read timeout of 0, so that the read attempt returns immediately when no data has arrived yet.