The latest release 3.0a of uLisp includes a feature from Common Lisp that I think will be especially useful on small memory implementations of uLisp: the #. read-time eval macro. This causes the atom or form after the #. to be evaluated when the code is read in.
To illustrate its use here’s a simple example.
A familiar routine to get the decimal value of a hexadecimal character is:
(defun hex (h)
(let ((c (char-code h)))
(cond
((<= (char-code #\0) c (char-code #\9))
(- c (char-code #\0)))
((<= (char-code #\A) c (char-code #\F))
(- c (- (char-code #\A) 10))))))
For example:
> (hex #\F)
15
It’s pretty clear to see what’s going on here, but we can write it more efficiently like this:
(defun hex (h)
(let ((c (char-code h)))
(cond
((<= 48 c 57)
(- c 48))
((<= 65 c 70)
(- c 55)))))
However, now the meaning is much more obscure. For example, what’s “55” doing here?
With the #. read-time eval macro we can have the best of both worlds; a legible program, but efficient code:
(defun hex (h)
(let ((c (char-code h)))
(cond
((<= #.(char-code #\0) c #.(char-code #\9))
(- c #.(char-code #\0)))
((<= #.(char-code #\A) c #.(char-code #\F))
(- c #.(- (char-code #\A) 10))))))
When this is read in, uLisp evaluates the forms after each #. read-time eval macro, and stores the result in the code. We can see this if we prettyprint the definition:
> (pprintall)
(defun hex (h)
(let ((c (char-code h)))
(cond ((<= 48 c 57) (- c 48)) ((<= 65 c 70) (- c 55)))))
This not only reduces the code size, but makes the execution faster.
You can also include global variables in the code being evaluated at read-time. For example, you could now write the definition of diff more efficiently from my forum topic GPS interface using uLisp:
(defvar *degree* 600000)
(defun diff (deg1 deg2)
(let ((result (- deg2 deg1)))
(cond
((> result #.(* *degree* 180)) (- result #.(* 360 *degree*)))
((< result #.(* *degree* -180)) (+ result #.(* 360 *degree*)))
(t result))))