Pocket Scheme - Applications

Applications written in Scheme do exist. If they refrain from using implementation-dependent features, Pocket Scheme can run them.

SLIB | JACAL | Schelog | Scheme Prolog | Porting others

SLIB

Pocket Scheme supports Aubrey Jaffer's SLIB portable Scheme library.

  1. Assume that Pocket Scheme installs into the directory \Program Files\Pocket Scheme. If not, you will need to alter the following instructions and edit a single line in the SLIB initialization file (q.v.).
  2. Download the latest version of SLIB (3a3 as of this writing).
  3. On your device, create the directory \Program Files\Pocket Scheme\slib.
  4. Unzip the SLIB archive. Copy all of the .scm files to the new directory. Optionally, copy .txt, .ps, and .xyz files as well.
  5. Copy this SLIB initialization file to your \Program Files\Pocket Scheme directory. Call it slibinit.scm or some such. (The file has some issues— see the note below about output-port-width— but it'll get you going.)
  6. To reduce the amount of storage occupied by SLIB, remove the files mitcomp.pat, slib.texi, ChangeLog, Makefile, and all the *.init files. If you're just using SLIB to run other applications (e.g. JACAL), remove the documentation file slib.info.
  7. Launch Pocket Scheme.
  8. Load the initialization file slibinit.scm. (load "/program files/pocket scheme/slibinit.scm").
  9. With that loaded, you have SLIB. Try (require 'random) - note the single quote, this is SLIB's version of REQUIRE - followed by (random 100) to see SLIB do something other than print loading prompts. If this fails, then you probably need to modify the definition of SLIB's library-vicinity (which is not the same thing as Pocket Scheme's own library-directory) in slibinit.scm.

Upon being loaded, SLIB redefines the require procedure to its own ends. Pocket Scheme's previous definition of this procedure remains available as pscheme:require. SLIB performs its own library management, so there is no need to set the library directory to the slib directory.

Note that your downloaded distribution of SLIB may contain a old version of the initialization file under the name pscheme.init. Please examine your copy to ensure that you're using the most recent version.

Notes

The make-crc package as supplied in SLIB assumes that any read-char will return a value of no more than 8 bits. (Actually, it assumes no such thing, hiding that assumption behind a symbol named char-code-limit; however, its algorithm makes it effectively unusable on a palmtop computer with that symbol set to 65536.)

There are issues about binary I/O with 3-series SLIB and Pocket Scheme 1.2. Many portions of SLIB assume that any read-char consumes 8 bits from a backing file. I have yet to address this.

If you'd rather keep SLIB on a storage card, edit the definition of library-vicinity in slibinit.scm.

JACAL

Pocket Scheme can host JACAL, Aubrey Jaffer's interactive symbolic math program. This yields a powerful computer algebra system on your Windows CE device - a handheld Macsyma, if you will.

  1. Install SLIB (q.v.).
  2. Download the latest version of JACAL, (1b4 as of this writing).
  3. On your device, create the directory \Program Files\Pocket Scheme\jacal.
  4. Unzip the JACAL archive. Copy all of the files to the new directory. You can leave out the docs. jacalcat, however, is important.
  5. Launch Pocket Scheme.
  6. Enable a fixed-pitch font: View/Fixed-pitch Font. JACAL's formula formatting assumes monospacing. (JACAL's formula formatting also assumes that slibinit.scm knows how many characters will fit onto one line of the console. Review the output-port-width procedure in that file. The correct value for it to return will depend on your device, the font, the size of the font... try 30 as a first guess. Of course you'll need to do this before calling require.)
  7. Initialize SLIB: (load "/program files/pocket scheme/slibinit.scm").
  8. Now load JACAL: (slib:load "/program files/pocket scheme/jacal/math.scm"). Note that this uses slib:load instead of load.
  9. Start JACAL: (math)
  10. Enter batch("/program files/pocket scheme/jacal/demo"); - note the semicolon and the parenthesis placement, as this is now JACAL syntax, not Scheme.
  11. If you want to exhaust Pocket Scheme's default 1Mb heap, do some heavy lifting with batch("/program files/pocket scheme/jacal/test.math");. Alternately, you can visit Tools - Configure, enlarge the heap, Tools - Exit, restart Pocket Scheme, and resume from the (load "slibinit.scm") step above. 2048Kb seems enough.

Note that JACAL plus SLIB will require almost 1.3Mb of storage (uncompressed) on the device simply to store its source files. You can of course cull unused parts of SLIB to reduce this.

Notes

As a long-term goal, I want to make Pocket Scheme host JACAL more gracefully. The current tty-style user interface is acceptable on a keyboard-equipped Handheld PC, but quite unpleasant to use on a Pocket PC. I would also like to see some integration with graphing functions, such as the one I have prototyped in the sample code as plot.scm.

If you find JACAL failing simple operations such as (b-a)^(1/2), check to make sure that the symbol char-code-limit has value 256. The most recent version of the SLIB initialization file sets this correctly.

Schelog

Pocket Scheme can host Schelog, Dorai Sitaram's embedding of Prolog-style logic programming in Scheme.

After downloading Schelog, simply follow the installation directions therein, identifying your Scheme dialect as pscheme, and your operating system (if necessary) as windows. (Versions of Schelog previous to 3h2 will require that you examine and possibly modify Schelog's makeport.scm to generate the correct syntax for Pocket Scheme.) Rename the resulting file with the extraordinarily long filename to something that won't provoke tendonitis.

To test your Schelog installation, try the map-coloring example. Be sure that you have verbosity set to 3 or less. Assuming that you renamed the ported Schelog to s.scm:

(load "/Program Files/Pocket Scheme/schelog/s.scm")
(load "/Program Files/Pocket Scheme/schelog/examples/mapcol.scm")
(%which (M) (%test-color 'test M))

This simple map-coloring test will yield a total of 120 non-unique permutations. You can see them all without typing (%more) 119 times via

(do 
 ((i 1 (+ i 1)) (f (%which (M) (%test-color 'test M)) (%more)))
 ((not f) "No more solutions")
 (display "*** Sol'n #") (display i) (display ": ") (display f) (newline))

Comparison with Edinburgh-syntax Prolog

Here's a simple Prolog program that sorts a list of numbers.

bsort(List, Slist) :- 
  swap(List, List0), !, bsort(List0, Slist).
bsort(Slist, Slist).
swap([X, Y|T] , [Y, X|T]) :- not(ordered(X, Y)).
swap([H|T], [H|T0]) :- swap(T, T0).
ordered(X, Y) :- X < Y.

In Schelog, this bubble sort becomes

(define %bsort
 (letrec
  ((swap
    (%rel (x y t h t0)
     (((cons x (cons y t)) (cons y (cons x t))) 
      (%not (ordered x y)))
     (((cons h t) (cons h t0)) 
      (swap t t0)) ))
   (ordered
    (%rel (x y)
     ((x y) 
      (%< x y)) )))
  (%rel (l s l0)
   ((l s) (swap l l0) ! (%bsort l0 s))
   ((s s)) )))

Here's Prolog to solve the Eight Queens problem.

queens(N, Qs) :- 
  range(1, N, Ns), queens(Ns, [], Qs).
queens([], Qs, Qs).
queens(UnplacedQs, SafeQs, Qs) :- 
  select(Q, UnplacedQs, UnplacedQs1),
  not(attack(Q, SafeQs)), 
  queens(UnplacedQs1, [Q|SafeQs], Qs).
select(X, [X|Xs], Xs).
select(X, [Y|Ys], [Y|Zs]) :- 
  select(X, Ys, Zs).
attack(X, Xs) :- 
  attack(X, 1, Xs).
attack(X, N, [Y|Ys]) :- 
  X is Y + N; X is Y - N.
attack(X, N, [Y|Ys]) :- 
  N1 is N + 1, attack(X, N1, Ys).
range(M, N, [M|Ns]) :- 
  M < N, M1 is M + 1, range(M1, N, Ns).
range(N, N, [N]).

In Schelog, this becomes

(define %queens
 (letrec ((select
           (%rel (x xs y ys zs)
            ((x (cons x xs) xs))
            ((x (cons y ys) (cons y zs)) 
             (select x ys zs)) ))
          (attack
           (%rel (x xs n n1 y ys)
            ((x xs) 
             (attack x 1 xs))
            ((x n (cons y ys)) 
             (%is x (+ y n)))
            ((x n (cons y ys)) 
             (%is x (- y n)))
            ((x n (cons y ys)) 
             (%is n1 (+ n 1)) (attack x n1 ys)) ))
          (range
           (%rel (m m1 n ns)
            ((m n (cons m ns)) 
             (%< m n) (%is m1 (+ m 1)) (range m1 n ns))
            ((n n (list n))) )))
  (%rel (n ns q qs uq uq1 sq)
   ((n qs) 
    (range 1 n ns) (%queens ns '() qs))
   (('() qs qs))
   ((uq sq qs) 
    (select q uq uq1) (%not (attack q sq)) (%queens uq1 (cons q sq) qs)) )))

These two examples highlight a number of differences between Prolog and Schelog:

Schelog performance

Schelog extensively uses reified Scheme continuations, which are an expensive feature in Pocket Scheme. It is possible that some instances of call-with-current-continuation could be replaced with call-with-escape-continuation for a performance improvement both in runtime and working-set size.

Scheme Prolog

Pocket Scheme can host Scheme Prolog 1.2, John Cleary et al's implementation of pure Prolog in Scheme.

After editing prolog.ss to specify the location of the sourcefiles, you will need to add the following definitions to compatibility.ss:

(define last-pair last)
(define 1+ (lambda (x) (+ x 1)))
(define 1- (lambda (x) (- x 1)))
(define cpu-time (lambda () 0))
(define flush-output-port force-output)
(define list-copy (lambda (x) (append x '())))

Scheme Prolog examples

This Prolog focuses on interval arithmetic operations, which makes its output for less specialized numeric operations somewhat unintuitive. Consider the following simple Prolog program that calculates the length of a list.

length([], 0).
length([_|T], Len) :- length(T, Len0), Len is Len0 + 1.

In Scheme Prolog, you would express this as

(when (length ?L ?N))
(what (length () 0))
(what (length (?H . ?T) ?N) (length ?T ?N0) (add ?N0 1 ?N))

Querying the length of a list (1 2 3) through this relation via ((length (1 2 3) ?x)) yields the answer (< 3 3 >), the arithmetic interval whose open lower bound is 3 and open upper bound is 3. That is, the integer 3.

Comparison with Schelog

For purposes of comparison, Schelog would express the previous length relation like this:

(define %length
 (%rel (h t l l0)
   (('() 0))
   (((cons h t) l) (%length t l0) (%is l (+ l0 1))) ))
and answer the query via (%which (X) (%length '(1 2 3) X)).

Schelog programs are Scheme programs that contain Prolog-style relations and unifications. The Schelog user works from the Scheme prompt, manipulating Scheme expressions. In contrast, Scheme Prolog programs are Prolog programs: the Scheme Prolog user starts from the Scheme prompt, starts the Scheme Prolog program with a database of Scheme Prolog relations, and works from the Prolog ?- prompt thereafter. Hence Scheme Prolog is free to use a somewhat more traditional syntax.

Porting other applications

Sometimes a program written to a different Scheme environment needs modification before Pocket Scheme can host it. Here are some of the differences that I've observed.

  1. Macros. The standard, sanctioned Scheme macro facility only entered the language with R5RS in 1998 (though R4RS of 1991 specified macros in an appendix). Hence many different macro facilities exist. Pocket Scheme uses the non-hygienic Gambit define-macro, and includes defmacro in its SLIB support. If you need a full R5RS syntax-rules macro facility, consider the Macro By Example implementation within SLIB, or Macros That Work if you absolutely must have the let-syntax and letrec-syntax forms.
  2. Numerics. Pocket Scheme does not support complex numbers, in either polar or rectangular notation. (Prior to version 1.1.0 it had much more limited numerics - Palm-size PC users, take note.) You will not be able to run code that presumes complex numbers without cobbling together your own support for them. And the sequence (do ((i -5 (+ i 0.1))) ((= i 5) (newline)) (display i) (display #\space)) never terminates, due to an accumulation of floating-point arithmetic inaccuracies.
  3. Character size. Pocket Scheme natively supports Unicode text, and so may return a value greater than 255 from char->integer. Many applications and libraries contain code that assumes that it can use the return value of char->integer as an index into a vector with 256 elements. So long as that code never encounters characters outside the Latin-1 character set, this will work; but once the application migrates to Russia or Japan, it will fail. Changing such code to index a vector of 65536 elements is usually not a good idea.
  4. Implementation-specific features. Many Scheme programs exist that use C-style escape sequences within string constants, or additional named character constants, or alternate parenthesis characters. Since Pocket Scheme doesn't support any sort of user-bindable read-table (Common Lisp style), you'll have to crawl the text of the programs in question to make these changes. A missing procedure or syntax unique to a particular implementation is easy to remedy: simply supply it yourself with define or define-macro.
  5. OS-specific features. This may come as a shock, but Windows CE is not UNIX. Pocket Scheme abstracts over a few of the differences, implementing itself the notion of current working directory, and translating slashes to backslashes in pathnames where necessary. A dependency on other operating system features, such as environment variables or even procedures that map to the POSIX API, will require changes to the application.

Other destinations

Pocket Scheme
Back to the Pocket Scheme page.
Site Map
Find your way around this site

Last modified: Wed Apr 05 10:34:09 Pacific Standard Time 2006

Ben Goetter (contact information)

Copyright 1998-2006, Ben Goetter. All rights reserved.