Preloading functions in uLisp

Suppose you want to have a selection of your own favourite Lisp functions available whenever you start up uLisp. What's the best way to do this, and what are the pros and cons of each?

There are now three different ways to do this:

  • Saved image: Save an image of the workspace containing the functions, and make it load automatically at startup.
  • Lisp Library: Add the definitions of your functions at the start of the uLisp source in the LispLibrary string, and make them load automatically at startup.
  • Extensions File: Define the functions in C in a separate Extensions File.

The pros and cons of each of these methods of adding functions are summarised in the following table, and each method is described in greater detail below:

Method Written in Uses up Lisp workspace Need to edit uLisp source Can still use save-image
Saved image Lisp Yes Only first time No
Lisp Library Lisp Yes Yes Yes
Extensions File C No Yes Yes

I'll demonstrate each of these methods by providing the function remove:

(defun remove (x lst)
  (cond
   ((null lst) nil)
   ((eq x (car lst)) (remove x (cdr lst)))
   (t (cons (car lst) (remove x (cdr lst))))))

This returns a copy of lst with items eq to x removed:

> (remove 'the '(the cat sat on the mat))
(cat sat on mat)

> (remove 'dog '(the cat sat on the mat))
(the cat sat on the mat)

Saved image

uLisp can automatically load a saved image on startup, and optionally run a specified function.

To make uLisp automatically reload a saved image you first need to uncomment the directive:

#define resetautorun

and recompile and upload uLisp.

Now, define remove as shown above, and save the current Lisp workspace by entering:

(save-image)

After restarting uLisp you can confirm that your functions have been loaded by typing:

(pprintall)

Running a specified function

You can also specify a function with no parameters that will be run on startup. For example, the following function flashes the built-in LED:

(defun flash ()
  (pinmode :led-builtin t)
  (digitalwrite :led-builtin t)
  (delay 500)
  (digitalwrite :led-builtin nil))

Now save the current Lisp workspace, specifying the function name as a parameter to save-image:

(save-image 'flash)

After restarting uLisp the saved image will be loaded, and the function flash will be run, so you should see the LED flash.

Lisp Library

The Lisp Library feature allows you to extend uLisp with your own library of function or variable definitions written in Lisp. The definitions are stored in the uLisp source file, as text strings in a C string called LispLibrary[].

You have to do a small amount of formatting to make the uLisp function definitions compatible with C strings. For example, you have to enclose each line of the function in double quotes, and escape any double quotes that occur in the Lisp function:

// Lisp Library
const char LispLibrary[] PROGMEM =
"(defun remove (x lst)"
"  (cond"
"   ((null lst) nil)"
"   ((eq x (car lst)) (remove x (cdr lst)))"
"   (t (cons (car lst) (remove x (cdr lst))))))";

For a full explanation, with examples, see Lisp Library.

For several useful functions you might like to provide see: Adding useful functions to uLisp.

To make the functions you have defined load at startup you need to uncomment the #define:

#define lisplibrary

and recompile and upload uLisp.

Again, you can confirm that your functions have been loaded by typing:

(pprintall)

Extensions file

As of release 4.4 of uLisp you can extend uLisp without needing to edit the original uLisp source file, by including extra user functions in a separate Extensions file.

The functions need to be written in C, and so this requires a greater degree of programming knowledge, and also requires you to understand how functions are implemented in uLisp. However, for some tasks, such as adding functions to uLisp to interface with an external library, this is the only way to do it. For more information see Adding your own functions.

Here's a possible implementation of the Lisp remove function in C:

object *remove (object *x, object *lst) {
  if (lst == NULL) return nil;
  else if (x == car(lst)) return remove(x, cdr(lst));
  else return cons(car(lst), remove(x, cdr(lst)));
}
  
object *fn_remove (object *args, object *env) {
  (void) env;
  return remove(first(args), second(args));
}

// Symbol names
const char stringremove[] PROGMEM = "remove";

// Documentation strings
const char docremove[] PROGMEM = "(remove x lst)\n"
"Returns a copy of lst with items eq to x removed.";

// Symbol lookup table
const tbl_entry_t lookup_table2[] PROGMEM = {
  { stringremove, fn_remove, 0222, docremove },
};

This defines it recursively, just like the Lisp version, to show how you can do an almost direct conversion from Lisp to C.

Here's the whole Extensions file that you can compile with uLisp to incorporate this function: Remove Extension file