Lisp Library

The Lisp Library feature allows you to extend uLisp with your own library of function or variable definitions written in Lisp. They are stored as text in flash memory along with the uLisp code, and get loaded when you run uLisp.

You can either load the entire Lisp Library when uLisp starts, or you can load individual function or variable definitions using require.

You can also list the functions and variables defined in the Lisp Library using list-library.

Note that this is separate from save-image and load-image, which use the processor's EEPROM or flash memory, or an SD card. The Lisp Library can be used even on platforms with no EEPROM or SD card, where save-image and load-image are not available. Where they are available you can still use them to save a snapshot of your workspace without affecting the Lisp Library.

For a file containing several useful functions you might like to provide in a Lisp Library see:

Adding useful functions to uLisp

Update

5th November 2023: This page has been updated to incorporate the use of a C++ Raw String Literal to avoid needing to enclose each Lisp Library line in double quotes, and escape special characters.

Defining a Lisp Library

For example, suppose you would like your uLisp environment to include these square and cube functions:

(defun square (x) (* x x))
(defun cube (x) (* x x x))

In the uLisp source

You can define these as a Lisp Library by editing the definition of LispLibrary[] at the start of your uLisp source to:

const char LispLibrary[] PROGMEM = R"lisplibrary(

(defun square (x) (* x x))
(defun cube (x) (* x x x))

)lisplibrary";

This uses a C++ Raw String Literal to avoid needing to enclose each Lisp Library line in double quotes, or escape special characters.

Note: on the ESP8266 omit the PROGMEM.

In a separate LispLibrary.h file

Alternatively, you can keep your Lisp Library definitions separate from the uLisp source code by creating a separate LispLibrary.h file in the same Arduino project folder as the uLisp source file, and put the definition in that.

Comment out the definition of LispLibrary[] at the start of the uLisp source:

// Lisp Library
// const char LispLibrary[] PROGMEM = "";

Then add a reference to the LispLibrary.h file in the main source file by uncommenting the line:

#include "LispLibrary.h"

Direct commands

You can include a direct call to a function to run a program when the processor is reset.

For example, defining the following Lisp Library:

const char LispLibrary[] PROGMEM =  R"lisplibrary(

(defun blink (x) (pinmode 13 t) (digitalwrite 13 x) (delay 1000) (blink (not x)))
(blink t)

)lisplibrary";

will cause the program to run and blink the LED when the processor is reset.

Loading the Lisp Library

Loading the entire Lisp Library at startup

To load all the functions and variables defined in the Lisp Library at startup uncomment the #define:

#define lisplibrary

Loading an individual function or variable definition

To load individual functions or variable definitions only when you need them, leave the #define commented:

// #define lisplibrary

and give a command such as:

(require 'square)

Listing the contents of the Lisp Library:

To list the functions and variables defined in the Lisp Library use the list-library command. For example:

> (list-library)
square cube

Creating a Lisp library

Listing programs

A convenient way to create a Lisp Library is as follows:

  • Define the functions you want to include in the Lisp Library, and test them from the Serial Monitor.
  • List the functions in the workspace with the command:
(pprintall)
  • Select the listings from the Serial Monitor window and paste them into the source window.
  • Add the line:
const char LispLibrary[] PROGMEM =
  • Add the double quotes at the start and end of each line, and a final semicolon.
  • Escape double quotes in your source, where necessary, as described in the next section.

Quoting and escapes

You can avoid needing to enclose the Lisp statements in quotes, or escape special characters, by defining them as a C++ Raw String Literal by enclosing them between the delimiters:

R"lisplibrary(

and

)lisplibrary";

The identifier lisplibrary in these is arbitrary, and is just to ensure that the terminating sequence doesn't occur anywhere in the string literal.