Language reference

Summary

Symbols

nil, t, nothing

Reader macros

#', #*, #., #\, #(, #nA, #|, #b, #o, #x

List functions

cons, car, first, cdr, rest, caar, cadr, second, cdar, cddr, caaar, caadr, cadar, caddr, third, cdaar, cdadr, cddar, cdddr, list, append, length, reverse, nth, sort

Array functions

make-array, length, aref, arrayp, array-dimensions

Defining variables and functions

lambda, defun, defvar, setq, set, let, let*

Arithmetic functions

+, -, *, /, mod, 1+, 1-, abs, random, max, min

Arithmetic comparisons

=, <, <=, >, >=, /=, plusp, minusp, zerop, oddp, evenp

Bitwise operations

logand, logior, logxor, lognot, ash, logbitp

Conditionals

if, cond, when, unless, case, and, or, not

Tests

null, atom, listp, consp, numberp, streamp, eq, equal, symbolp, boundp

Characters

char, char-code, code-char, characterp

Strings

string<, string=, string>, stringp, string, concatenate, read-from-string, prin1-to-string, princ-to-string,
with-output-to-string

Strings and lists

subseq, search

Iteration and mapping

loop, return, dolist, dotimes, mapc, mapcar, mapcan, progn, assoc, member, funcall, apply, eval

In-place operations

setf, push, pop, incf, decf

Error handling

unwind-protect, ignore-errors, error

Documentation

?, documentation, apropos, apropos-list

Input/output

read, print, princ, prin1, pprint, pprintall, terpri, read-byte, write-byte, read-line, write-line, write-string, format

System functions

globals, makunbound, break, gc, save-image, load-image, edit, room, time, trace, untrace, sleep, require, list-library, register

Arduino interface

millis, for-millis, with-i2c, restart-i2c, with-serial, with-spi, with-sd-card, pinmode, digitalread, digitalwrite, analogread, analogreference, analogreadresolution, analogwrite, analogwriteresolution, delay, note

Floating-point extensions

For the floating-point extensions see Floating-point extensions.


#' reader macro

Ignored.

The sequence #' is ignored, to allow you to paste in Common Lisp programs that need to include it before function names in some contexts.

#* reader macro

Introduces a one-dimensional bit array. For example:

> #*10100100010000

#. reader macro

The atom or form after the #. is evaluated when the code is read in.

#\ reader macro

Allows you to enter a character.

The sequence #\ can be followed by one of the following three options:

  • A single ASCII character
  • One of the following strings representing a control code:

Null, SOH, STX, ETX, EOT, ENQ, ACK, Bell, Backspace, Tab, Newline, VT, Page, Return, SO, SI,
DLE, DC1, DC2, DC3, DC4, NAK, SYN, ETB, CAN, EM, SUB, Escape, FS, GS, RS, US, Space

  • A number between 000 and 255 representing the decimal character code of the character.

#( reader macro

Introduces a one-dimensional array.

For example:

> #(6 28 496 8128)
#(6 28 496 8128)

#nA reader macro

Introduces an n-dimensional array.

For example:

> #2A((1 2 3) (2 4 6))
#2A((1 2 3) (2 4 6))

#| reader macro

Introduces a multi-line comment.

All the text between #| and |# is ignored.

#b, #o, #x reader macros

Allow you to enter numbers in binary, octal, or hexadecimal notation.

For example:

> #xFFFF
-1

> #b0101010101010101
21845

> #o777
511

special form

Syntax: 'item

Quotes the argument.

'(+ 1 2)

is a shorthand for:

(quote (+ 1 2))

function

Syntax: (* number*)

Multiplies its arguments together.

function

Syntax: (+ number*)

Adds its arguments together.

function

Syntax: (- number*)

If there is one argument, negates the argument.

If there are two or more arguments, subtracts the second and subsequent arguments from the first argument.

function

Syntax: (/ number*)

If there is one argument, inverts the argument (floating-point platforms only).

If there are two or more arguments, divides the first argument by the second and subsequent arguments.

For example:

> (/ 60 2 3)
10 

/= function

Syntax: (/= number*)

Not equal. Returns t if none of the arguments are equal, and nil if two or more arguments are equal.

A potential source of confusion is that this function is called "!=" in C.

1+ function

Syntax: (1+ number)

Adds one to its argument and returns it.

> (1+ (* 3 3))
10 

(1+ x) is a shorter way of writing (+ x 1).

1- function

Syntax: (1- number)

Subtracts one from its argument and returns it.

> (1- (* 3 3))

(1- x) is a shorter way of writing (- x 1).

; (semicolon)

Introduces a comment line, which will be ignored. For example:

; Factorial function
(defun f (n) (if (= n 0) 1 (* n (f (- n 1)))))

Because the Arduino Serial Monitor removes line endings uLisp ignores all characters after a semicolon up to the next opening bracket. This imposes a couple of restrictions in the use of comments:

  • Comments should not include an opening bracket.
  • Comments are not valid if they are not followed by an opening bracket; for example:
(defvar data '(#x01 ; Invalid comment
  #x20))

In this situation you can use a multi-line comment instead; see #|.

A comment line turns off echo so that by starting a long listing with a comment, it can safely be pasted in to the Arduino IDE's Serial Monitor without overflowing the serial buffer. Echo is turned back on automatically after a one second delay if there is no activity on the serial input.

function

Syntax: (< number*)

Returns t if each argument is less than the next argument, and nil otherwise.

<= function

Syntax: (<= number*)

Returns t if each argument is less than or equal to the next argument, and nil otherwise.

function

Syntax: (= number*)

Returns t if the arguments are numerically equal, and nil otherwise.

For example:

> (= (* 4 3) (* 2 6) (* 1 12))

To add documentation to a user-defined function see defun.

function

Syntax: (> number*)

Returns t if each argument is greater than the next argument, and nil otherwise.

>= function

Syntax: (>= number*)

Returns t if each argument is greater than or equal to the next argument, and nil otherwise.

special form

Syntax: (? symbol)

Prints documentation about the built-in or user-defined function symbol.

For example:

> (? assoc)
(assoc key list)
Looks up a key in an association list of (key . value) pairs,
and returns the matching pair, or nil if no pair is found.

For information about adding documentation to a user-defined function see defun.

abs function

Syntax: (abs number)

Returns the absolute, positive value of its argument.

analogread Arduino function

Syntax: (analogread pin)

Reads the specified Arduino analogue pin number and returns the value.

For details of the available pins see the appropriate board description on this site.

On most processors the analogue inputs are 10 bits, so the value is a number between 0 and 1023.

If you prefer to use the pin labels A0, A1, etc you can define appropriate variables; for example, for the Arduino Zero:

(defvar A0 15)

analogreadresolution Arduino function

Syntax: (analogreadresolution bits)

Sets the analogue read resolution for the analogue inputs on platforms that support it. The default resolution on all platforms is 10 bits.

For details of the options available see the appropriate board description on this site.

analogreference Arduino function

Syntax: (analogreference keyword)

Selects the analogue reference voltage used for analogue input.

For details of the available keywords see the appropriate board description on this site.

analogwrite Arduino function

Syntax: (analogwrite pin value)

Writes the value to the specified Arduino pin number.

For details of the available pins see the appropriate board description on this site.

On most processors the analogue outputs are 8 bits, so the value is a number between 0 and 255. For example:

(analogwrite 3 127)

analogwriteresolution Arduino function

Syntax: (analogwriteresolution value)

Sets the analogue write resolution.

and special form

Syntax: (and item*)

Evaluates its arguments until one returns nil, and returns the last value. It's usually used to combine conditions. For example, pos tests whether something is a positive number:

(defun pos (a) (and (numberp a) (> a 0)))

append function

Syntax: (append list*)

Joins its arguments, which should be lists, into a single list.

For example:

> (append '(1 2 3) '(4 5 6) '(7 8 9))
(1 2 3 4 5 6 7 8 9) 

apply function

Syntax: (apply function list)

Returns the result of evaluating the function specified by the first argument with the list of arguments specified by the second parameter. So, for example:

> (apply cons '(a b))
(a . b)

This is equivalent to (cons 'a 'b).

apropos function

Syntax: (apropos item)

Prints the user-defined and built-in functions and variables whose names contain the specified string or symbol.

This function is not available in the AVR-Nano version of uLisp.

For example:

> (defun catty () "meow")
catty

> (apropos "cat")
catty (user function)
truncate (function)
concatenate (function)

You could also write:

(apropos 'cat)

apropos-list function

Syntax: (apropos-list item)

Returns a list of the user-defined and built-in functions and variables whose names contain the specified string or symbol.

This function is not available in the AVR-Nano version of uLisp.

For example:

> (defun catty () "meow")
catty

> (apropos-list "cat")
(catty truncate concatenate)

You could use this to write a function that prints out the documentation for all functions containing a string:

(defun all-doc (pat)
  (mapc #'(lambda (symbol) (format t "~a~%~%" (documentation symbol))) (apropos-list pat))
  nothing)

For example, try:

> (all-doc 'map)

array-dimensions function

Syntax: (array-dimensions item)

Returns a list of the dimensions of an array. For example:

> (array-dimensions #2A((1 2) (3 4) (5 6)))
(3 2)

You can also use length to get the length of a one-dimensional array.

arrayp function

Syntax: (arrayp item)

Returns t if its argument is an array.

aref function

Syntax: (aref array index [index*])

Returns an element from the specified array. The aref function can be used to return a value as in:

(print (aref a 99))

To access elements in a multi-dimensional array you need to give an index for each dimension; for example:

(print (aref b 2 3))

The aref function can also be used with the in-place operations setfincf, and decf to change an element of an array; for example, to change the value of an array element:

(setf (aref b 42) 3.14159)

or to increment an element:

(incf (aref c 99))

ash function

Syntax: (ash value shift)

Returns the result of bitwise shifting value by shift bits. If shift is positive, value is shifted to the left. For example:

> (ash 7 3)
56

If shift is negative, value is shifted to the right. For example:

> (ash 15 -2)
3

The right shift is an arithmetic shift, so the sign bit is preserved; for example:

> (format t "~x" (ash #x8000 -8))
ff80

assoc function

Syntax: (assoc key list)

Looks up a key in an association list of (key . value) pairs, and returns the matching pair, or nil if no pair is found.

Example:

> (assoc 'c '((a . 1) (b . 2) (c . 3) (d . 4)))
(c . 3)

Association lists are useful for storing complex data; for example you could use an association list to specify the colour of an RGB LED:

(setq col '((r . 127) (g . 63) (b . 255)))

You could then get one colour component using assoc:

> (cdr (assoc 'g col))
63 

atom function

Syntax: (atom item)

Returns t if its argument is a single number, symbol, or nil.

Example:

> (atom 'b)
t

> (atom '(a b))
nil 

The function atom is the inverse of consp.

boundp function

Syntax: (boundp item)

Returns t if the argument has a value or nil otherwise. 

> (boundp 'a)
nil

> (defvar a 23)
a

> (boundp 'a)
t

break function

Syntax: (break)

Inserts a breakpoint in your uLisp program.

When the (break) function is evaluated you will be returned to the uLisp prompt, and you can then examine the values of parameters and local variables.

The uLisp prompt is preceded by a number giving the break level. Type nil to exit from break and continue execution.

For example:

> (let* (lis) (dolist (x '(a b c)) (setq lis (cons x lis)) (break)))

Break!
: 1> lis

(a)

: 1> nil

Break!
: 1> lis

(b a)

caaar ... cdddr function

Syntax: (caaar list)

These are all equivalent to the corresponding sequence of car and cdr functions. For example,

(cdaar list)

is equivalent to:

(cdr (car (car list)))

car function

Syntax: (car list)

Returns the first item in a list. 

> (car '(a b c d e f))
a

Equivalent to first.

case special form

Syntax: (case keyform ((key form*) (key form*) … ))

The case special form evaluates a keyform to produce a test key, and then tests this against a series of arguments, each of which is a list containing a key optionally followed by one or more forms.

If the test key equals the key the forms are evaluated, and the last value is returned as the result of the case. Otherwise none of the forms are evaluated, and the next argument is processed in the same way.

Specifying a key of t will always succeed.

In place of a single key you can specify a list of keys, any of which will match the test key.

The following example prints a different string according to the value of animal:

(case animal
   (cat (print "maiou"))
   (dog (print "woof"))
   ((sparrow thrush) (print "tweet"))
   (t (print "don't know"))

char function

Syntax: (char string n)

Returns the nth character in a string, counting from zero.

Example:

> (char "uLisp" 1)
#\L

char-code function

Syntax: (char-code character)

Returns the ASCII code for a character, as an integer.

For example:

> (char-code #\return)
13

characterp function

Syntax: (characterp item)

Returns t if the argument is a character and nil otherwise.

cdr function

Syntax: (cdr list)

Returns a list with the first item removed. 

> (cdr '(a b c d e f))
(b c d e f)

Equivalent to rest.

code-char function

Syntax: (code-char integer)

Returns the character for the specified ASCII code.

For example:

> (code-char 126)
#\~

concatenate function

Syntax: (concatenate 'string string*)

Joins together the strings given in the second and subsequent arguments, and returns a single string. The second argument specifies the type of the result; uLisp only supports string.

Example:

> (concatenate 'string "One" "Two" "Three")
"OneTwoThree"

cond special form

Syntax: (cond ((test form*) (test form*) … ))

The cond special form provides a more flexible conditional structure than the simpler functions if, while, and unless.

Each argument is a list consisting of a test optionally followed by one or more forms.

If the test evaluates to non-nil the forms are evaluated, and the last value is returned as the result of the cond.

If the test evaluates to nil, none of the forms are evaluated, and the next argument is processed in the same way.

The following example reads an analogue input and sets one of four outputs high depending on the value of the input:

(let* ((a (analogread 0)))
  (cond
   ((< a 64) (digitalwrite 2 t))
   ((< a 128) (digitalwrite 3 t))
   ((< a 192) (digitalwrite 4 t))
   (t (digitalwrite 5 t))))

As in this example, the last test in a cond is usually t to provide the action to be performed when all the previous tests fail.

cons function

Syntax: (cons item item)

If the second argument is a list, cons returns a new list with item added to the front of the list. For example:

> (cons 'a '(b c d e))
(a b c d e)

If the second argument isn't a list cons returns a dotted pair:

> (cons 'a 'b)
(a . b) 

consp function

Syntax: (consp item)

Returns t if its argument is a non-null list.

Example:

> (consp 'b)
nil

> (consp '(a b))

The function consp is the inverse of atom.

decf special form

Syntax(decf place [number])

Subtracts one from the value of place, and returns the new value. The second argument place can be one of the forms:

symbol
(car form)
(cdr form)
(nth n form)
(aref array index [index*]) 

For more information see setf.

For example:

> (defvar a 123)
a

> (decf a)
122

> a
122 

You can include an optional second argument to specify the decrement.

defun special form

Syntax: (defun name (parameters) [docstring] form*)

Allows you to define a function. For example:

(defun sq (x) (* x x))

This creates a function called sq with one parameter, x. When the function is called, the body is evaluated with x bound to the argument. For example:

> (sq 7)
49

This is equivalent to:

(defvar sq '(lambda (x) (* x x))

Optional arguments

You can specify optional arguments by giving the &optional keyword followed by the parameters you want to make optional. If an argument is not specified for an optional parameter it will have the value nil. For example, the following function rec calculates the area of a rectangle:

(defun rec (x &optional y) (if y (* x y) (* x x)))

It can be called with two arguments:

> (rec 3 4)
12

or one argument to calculate the area of a square:

> (rec 5)
25

You can specify a default value for any optional argument by specifying a list consisting of the optional argument followed by an expression. For example, the above definition could be written:

(defun rct (x &optional (y x)) (* x y))

Variable number of arguments

You can define a function that takes a variable number of arguments by giving the &rest keyword followed by a single parameter; this parameter is bound to a list of the remaining arguments.

For example, this defines a function out that defines any number of Arduino pins as outputs:

(defun out (&rest x) (mapc (lambda (p) (pinmode p t)) x))

You could call it with:

(out 4 5 6 7)

You can use both &optional and &rest in the same definition; for example:

(defun tst (x &optional y &rest z) (list "x=" x "y=" y "z=" z))

Trying it out:

> (tst 1 2 3 4 5)
("x=" 1 "y=" 2 "z=" (3 4 5))

Documentation

You can add documentation to a function by adding a documentation string docstring after the parameters. You can then display this using ? or documentation.

For example:

> (defun sq (x) "Squares a number" (* x x))
sq

> (? sq)
Squares a number

defvar special form

Syntax: (defvar variable form)

Defines a global variable. For example:

(defvar x 1000)

delay function

Syntax: (delay number)

Delays for a specified number of milliseconds. For example:

(delay 1000)

gives a one-second delay.

On the 16-bit platforms the maximum delay is 32767, or approximately 32 seconds. On the 32-bit platforms the maximum delay is 2147483647, or approximately 24 days.

See also for-millis.

digitalread Arduino function

Syntax: (digitalread pin)

Reads the state of the specified Arduino pin number and returns t (high) or nil (low).

The pin can also be the keyword :led-builtin.

digitalwrite Arduino function

Syntax: (digitalwrite pin state)

Sets the state of the specified Arduino pin number. The pins are the same as for digitalread above.

The pin can also be the keyword :led-builtin.

The state can be a keyword, or t or nil:

Keyword Description
:low or nil Low level
:high or t High level

documentation function

Syntax: (documentation 'symbol [type])

Returns the documentation string for the built-in or user-defined function symbol.

This function is not available in the AVR-Nano version of uLisp.

For example:

> (documentation 'nth)
"(nth number list)
Returns the nth item in list, counting from zero."

For information about adding documentation to a user-defined function see defun.

dolist special form

Syntax: (dolist (var list [result]) form*)

Sets the local variable var to each element of list in turn, and executes the forms. It then returns result, or nil if result is omitted.

dotimes special form

Syntax: (dotimes (var number [result]) form*)

Executes the forms number times, with the local variable var set to each integer from 0 to number-1 in turn. It then returns result, or nil if result is omitted.

For example, to flash an LED ten times:

(defun ten ()
  (pinmode 13 t)
  (dotimes (x 10)
    (digitalwrite 13 t)
    (delay 500)
    (digitalwrite 13 nil)
    (delay 500)))

edit function

Syntax: (edit 'function)

Lets you step through a function definition, editing it a bit at a time, using the following single-key editing commands:

Command Name Description
Enter enter Prettyprints the current form.
a car Takes the car of the current form.
d cdr Takes the cdr of the current form.
r replace Replaces the current form with what you type in.
c cons Conses what you type in onto the front of the current form.
x delete Deletes the car of the current form.
b back Backs up the tree.
q quit Quits from the editor.

To edit the function you type a series of a or d commands to step through the function to the part you want to edit, use r, c, or x to make changes, type b to go back, or type q to exit from the editor.

At any stage you can press Enter to print the current part of the function you've reached.

If you type an invalid key the editor prints ?, and if you reach the end of the tree with a or d the editor prints !. For more information see Using the program editor.

Note that for the editor to work properly you need to have the line ending option set to Newline on the pop-up menu at the bottom of the Serial Monitor window.

eq function

Syntax: (eq item item)

Tests whether the two arguments are the same object, and returns t or nil as appropriate.

Objects are eq if they are the same symbol, same character, equal numbers, or point to the same cons.

equal function

Syntax: (equal item item)

Tests whether the two arguments look the same when printed, and returns t or nil as appropriate. Note that they might not necessarily be the same object.

Objects are equal if they are eq, have the same string representation, or have the same list structure.

For example:

> (defvar a "twin")
a

> (defvar b "twin")
b

> (eq a b)
nil

> (equal a b)
t

error special form

Syntax: (error controlstring [arguments]*)

Signals an error. The message is printed by format using the controlstring and arguments.

eval function

Syntax: (eval form*)

Evaluates its argument an extra time.

For example:

> (eval (list '* 7 8))
56 

evenp function

Syntax: (evenp number)

Returns t if the argument is even, or nil otherwise.

first function

Syntax: (first list)

Returns the first item in a list. 

> (first '(a b c d e f))
a

Equivalent to car.

format function

Syntax: (format output controlstring arguments*)

Outputs its arguments formatted according to the format directives in the control string.

The output argument can be one of:

  • nil: the formatted output is returned as a string. For example:
> (format nil "The answer is ~a" 42)
"The answer is 42"
  • t: the formatted output is printed to the serial output. For example:
> (format t "The answer is ~a" 42)
The answer is 42
nil
  • a stream: the formatted output is printed to the specified stream.

Format directives

The control string can contain the following format directives:

Directive Name Description
~a ASCII Output as princ would print it in human-readable format.
~s Sexp Output as prin1 would print it, with escape characters and quotation marks.
~d Decimal Decimal, as princ would print it.
~b Binary Binary.
~x Hexadecimal Hexadecimal.
~g General General floating-point format, as princ would print it.
~~ Tilde Just prints a ~.
~% Newline Outputs a newline.
~& Newline Outputs a newline unless already at the start of a line.
~{ List start Formats elements from a list.
~^ List exit Exits from ~{ … ~} if the list is empty.
~} List end Ends formatting list elements.

Any other characters in the control string are just output unchanged.

For example:

> (format t "The battery is ~aV or ~a%." batt (* batt 20))
The battery is 4.75V or 95%.

If the argument is the wrong type for the directives ~d, ~b~x, or ~g the argument is output as if with ~a.

Width parameter

Each of the directives ~a, ~s, ~d, ~g, ~b, or ~x can include a width parameter after the tilde, and the output is padded with spaces to the specified width. If the output wouldn't fit in the specified width it is output in full, and overflows the width. The ~a and ~s directives pad with spaces to the right; all the other directives pad with spaces to the left. In uLisp this is the only difference between ~a and ~d or ~g.

The width parameter is useful for formatting data in a neat table. For example:

(defun facts ()
  (let ((n 1)) 
    (dotimes (x 10) 
      (format t "n = ~2d,  n! = ~7d~%" (1+ x) (setq n (* n (1+ x)))))))

This prints:

> (facts)
n =  1,  n! =       1
n =  2,  n! =       2
n =  3,  n! =       6
n =  4,  n! =      24
n =  5,  n! =     120
n =  6,  n! =     720
n =  7,  n! =    5040
n =  8,  n! =   40320
n =  9,  n! =  362880
n = 10,  n! = 3628800
nil

Pad character

The directives ~d, ~g, ~b, or ~x can also include a pad character, which is output in place of spaces to fill the argument to the specified width. The pad character is specified after the width, separated by a comma and a single quote. The pad character is useful combined with the width character for formatting output to be displayed on output devices such as seven-segment displays; for example:

> (format nil "~2,'0d-~2,'0d-~2,'0d" 1 45 7)
"01-45-07"

Lists

The ~{ and ~} directives allow you to format elements in a list. The argument must be a list, and the format directives between ~{ and ~} are repeated until all the items in the list have been used. For example:

> (format t "~{~a/~a ~}" '(1 2 3 4 5 6))
1/2 3/4 5/6

The ~^ directive exits from the directives between ~{ and ~} if the list being processed is finished. It is useful if you want to put a delimiter between list elements, but not after the last one. For example, to convert a Lisp list to JavaScript format you could use:

> (format t "[~{~a~^,~}]" '(1 2 3 4 5))
[1,2,3,4,5]

Note that uLisp only supports one level of nesting of ~{ and ~}.

for-millis Arduino function

Syntax: (for-millis ([number]) form*)

Executes the forms and then waits until a total of number milliseconds have elapsed. It returns the total number of milliseconds taken.

It can be used to define the duration of an event. For example, to play a one-second tone:

(defun bep () (for-millis (1000) (note 3 0 4)) (note))

Alternatively, if the number parameter is zero or omitted, for-millis can be used to time the execution of a function:

>  (for-millis () (fib 15))
493

On the 16-bit platforms the maximum delay is approximately 32 seconds. On the 32-bit platforms the maximum delay is approximately 24 days. If the execution of the body takes longer than this for-millis returns nil.

funcall function

Syntax: (funcall function argument*)

Calls the function with the specified arguments.

gc function

Syntax: (gc)

Forces a garbage collection and prints the number of objects collected, and the time taken.

globals function

Syntax: (globals)

Returns a list of the global variables and functions that are currently defined. For example:

> (globals)
(blu grn red)

if special form

Syntax: (if test then [else])

Evaluates test. If it's non-nil the form then is evaluated and returned; otherwise the form else is evaluated and returned.

The else form is optional.

For example:

> (if (digitalread 3) (digitalwrite 4 t) (digitalwrite 5 t))

This reads input D3. If it's high the LED on D4 is lit; otherwise the LED on D5 is lit.

ignore-errors special form

Syntax: (ignore-errors [forms]*)

Evaluates forms ignoring errors, and returns the value of the last form, or if an error occurs it returns the special value nothing

For example, the following function calc evaluates Lisp expressions you type in:

(defun calc ()
  (loop
   (let ((input (read)))
     (when (eq input '~) (return))
     (ignore-errors (format t "~%Result: ~a~%" (eval input))))))

Run it with:

> (calc)
(/ 1 2)
Result: 0.5

Without ignore-errors the calculator will exit if you type in an invalid expression, such as (/ 1 0).

incf special form

Syntax: (incf place [number])

Adds one to the value of place, and returns the new value. The second argument place can be one of the forms:

symbol
(car form)
(cdr form
(nth n form)
(aref array index [index*]) 

For more information see setf.

For example:

> (defvar a 123)
a

> (incf a)
124

> a
124

You can include an optional second argument to specify the increment.

lambda special form

Syntax: (lambda (parameter*) form*)

Creates an unnamed function with parameters. The body is evaluated with the parameters as local variables whose initial values are defined by the values of the forms after the lambda form.

Functions are usually defined with a specified name using defun. The usual use of lambda is to create an unnamed function as the argument for a function such as mapc or mapcar. For details of the options see defun.

Examples

For example, you could write:

((lambda (x y) (+ x y)) 4 3)

This would assign 4 to x and 3 to y, evaluate (+ x y), and return the result.

 The following example uses mapcar to square every number in a list:

> (mapcar (lambda (x) (* x x)) '(0 1 2 3 4 5 6))
(0 1 4 9 16 25 36)

It is also used when you want to create a function that returns a function. The following example defines a function do2 that takes a function of one argument, and returns a function that performs that function twice:

> (defun sq (x) (* x x))
sq

> (defun do2 (fun) (lambda (arg) (fun (fun arg))))
do2

> ((do2 sq) 3)
81

length function

Syntax: (length item)

Returns the number of items in a list, the length of a string, or the length of a one-dimensional array.

Examples:

> (length '(a b c d))
4
> (length "hello")
5
> (length #(1 4 9 16 25))
5

let special form

Syntax: (let ((var value) … ) forms*)

Declares local variables, and evaluates forms with those local variables.

In its simplest form you can declare a list of one or more variables which will be initialised to nil, and these can then be used in the subsequent forms:

(let (a b)
  (setq a 1)
  (setq b 2)
  (* a a b))

For each variable you can specify an initial value by specifying it as a list of (variable value), so the above example is equivalent to:

(let ((a 1) (b 2)) 
  (* a a b))

let* special form

Syntax: (let* ((var value) … ) form*)

Like let, but each declaration can refer to local variables that have already been defined.

For example, defining:

(defun tst ()
  (let ((a 7)
        (b a))
    (print a) (print b)))

and evaluating (tst) will give the error:

Error: 'a' undefined

whereas defining:
(defun tst (a)
  (let* ((a 7)
         (b a))
    (print a) (print b)))

and evaluating (tst) will print 7 7.

list function

Syntax: (list item*)

Returns a list of the values of its arguments.

Example:

> (list (* 1 1) (* 2 2) (* 3 3) (* 4 4))
(1 4 9 16) 

list-library function

Syntax: (list-library)

Prints a list of the functions defined in the List Library.

For example, if the Lisp Library is defined in the source file with:

const char LispLibrary[] PROGMEM =
"(defun sq (x) (* x x))"
"(defun cub (x) (* x x x))";

then you could list the library with:

> (list-library)
sq cub

For more information see Lisp Library.

listp function

Syntax: (listp item)

Returns t if its argument is a list.

Example:

> (listp 'b)
nil

> (listp '(a b))

The function listp differs from consp because (listp nil) is t whereas (consp nil) is nil.

load-image function

Syntax: (load-image [filename])

Loads a saved uLisp image from non-volatile memory or SD card.

On SD card, by default the image is saved to a file ULISP.IMG, but you can specify a string parameter to load the image from a file of that name.

Like save-image, the function returns the size of the image, in objects.

Note: You can make a saved uLisp image load automatically and run a specified function at startup; see save-image.

logand function

Syntax: (logand [value*])

Returns the bitwise logical AND of the values.

logbitp function

Syntax: (logbitp bit value)

Returns t if bit number bit in value is a '1', and nil if it is a '0'.

For example:

> (logbitp 0 1)

logior function

Syntax: (logior [value*])

Returns the bitwise logical OR of the values.

lognot function

Syntax: (lognot value)

Returns the bitwise logical NOT of the value.

logxor function

Syntax: (logxor [value*])

Returns the bitwise logical EXCLUSIVE-OR of the values.

loop special form

Syntax: (loop forms*)

The loop special form executes its arguments repeatedly until one of them reaches a return form, which exits from the loop.

For example, the following function b blinks an LED on I/O line 10 a specified number of times:

(defun b (x)
  (loop
   (digitalwrite 10 t)
   (delay 1000)
   (digitalwrite 10 nil) 
   (delay 1000) 
   (setq x (- x 1))
   (if (= x 0) (return))))

To blink the light 5 times execute:

> (b 5)
nil

make-array function

Syntax: (make-array size [:initial-element element[:element-type 'bit])

Arrays are not supported in the AVR-Nano version of uLisp.

If size is an integer make-array creates a one-dimensional array with elements from 0 to size-1. By default they are initialised to nil, but you can provide a default value with the :initial-element keyword parameter. For example:

(defvar a (make-array 100 :initial-element 0))

One-dimensional arrays are printed in the standard #( ... ) notation; for example:

> (make-array 3 :initial-element "Hello")
#("Hello" "Hello" "Hello")

If size is a list of n integers make-array creates an n-dimensional array. For example:

(defvar a (make-array '(2 3 4) :initial-element 0))

N-dimensional arrays are printed using the notation #nA( ... ), where n is the number of dimensions in the array. For example, the above array is printed as:

> a
#3A(((0 0 0 0) (0 0 0 0) (0 0 0 0)) ((0 0 0 0) (0 0 0 0) (0 0 0 0)))

You can read in an array using the same notation; for example:

(defvar a #2a((1 2 3) (4 5 6)))

Bit arrays

To make a bit array use the option :element-type 'bit. For example:

> (defvar b (make-array 40 :initial-element 0 :element-type 'bit))
b

One-dimensional bit arrays are printed using #* notation followed by a string of bits; for example:

> b
#*0000000000000000000000000000000000000000

For an example of using bit arrays see Prime number spiral.

Accessing or changing array elements

To access elements in arrays or bit arrays use the aref function.

To change elements in arrays or bit arrays use the setf, incf, or decf functions.

makunbound function

Syntax: (makunbound symbol)

Removes the definition of a function created with defun, or a global variable created with defvar, freeing up the space.

For example:

> (makunbound 'rgb)
rgb

The function will return the symbol.

mapc function

Syntax: (mapc function list1 [list]*)

Applies the function to each element in one or more lists, ignoring the results. It returns the first list argument.

For example:

> (mapc print '(1 2 3))
1
2
3
(1 2 3) 

The function mapc is like mapcar, but it doesn't accumulate a list of results, and so is used for its side-effects. For example, if you had an RGB LED connected to I/O pins 9, 10, and 11 you could set the colour of the LED to yellow with:

(mapc digitalwrite '(9 10 11) '(255 255 0))

For examples of using mapc and mapcar see Processing items in a list.

mapcan function

Syntax: (mapcan function list1 [list2]*)

Applies the function to each element in one or more lists. The results should be lists, and these are appended together to give the value returned by mapcan.

One use for mapcan is as a filter, to filter elements from a list if they don't meet a specified predicate. For example, to extract just the even numbers from a list:

> (mapcan (lambda (x) (if (evenp x) (list x))) '(2 7 1 8 2 8 1 8 2 8 4))
(2 8 2 8 8 2 8 4)

This example shows how mapcan can be used to interleave three lists:

> (mapcan list '(a b c d) '(1 2 3 4) '(w x y z))
(a 1 w b 2 x c 3 y d 4 z)

mapcar function

Syntax: (mapcar function list1 [list]*)

Applies the function to each element in one or more lists, and returns the resulting list.

The function can be a built-in function; for example:

> (mapcar * '(1 2 3) '(4 5 6) '(7 8 9))
(28 80 162) 

Alternatively it can be a user-defined function or a lambda expression; for example:

> (mapcar (lambda (x) (* x x)) '(1 2 3 4 5))
(1 4 9 16 25)

For examples of using mapc and mapcar see Processing items in a list.

max function

Syntax: (max number*)

Returns the maximum of one or more arguments. For example:

> (max 3 1 4 1 5 9 1 6)

member function

Syntax: (member item list)

Searches for an item in a list, using eq, and returns the list starting from the first occurrence of the item, or nil if it is not found.

For example:

> (member 's '(u l i s p))
(s p)

> (member 'x '(u l i s p))
nil 

millis Arduino function

Syntax: (millis)

Returns the time in milliseconds that uLisp has been running. On 8/16-bit versions of uLisp this is a signed 16-bit number, so after 32.767 seconds the number will wrap around from 32767 to -32768. In 32-bit versions of uLisp this is a signed 32-bit number which will wrap around after about 25 days.

See also for-millis.

min function

Syntax: (min numbers)

Returns the minimum of one or more arguments. For example:

> (min 3 1 4 1 5 9 1 6)

minusp function

Syntax: (minusp number)

Returns t if the argument is less than zero, or nil otherwise.

mod function

Syntax: (mod number number)

Returns its first argument modulo the second argument.

For example:

> (mod 127 10)

nil symbol

Syntax: nil

A symbol equivalent to the empty list ().

not function

Syntax: (not item)

Returns t if its argument is nil, or nil otherwise. Equivalent to null.

note Arduino function

Syntax: (note [pin] [note] [octave])

This is a lightweight replacement for the Arduino function tone. It generates a square wave on a digital pin.

It takes three arguments:

  • A pin number. The pins supported depend on the platform.
  • A note number, from 0 to 11, representing the note in the well-tempered scale, where 0 represents C, 1 represents C#, and so on.
  • The octave, which can be from 0 to 8*. If omitted it defaults to 0.

* On the ATmega328P, ATmega2560, and ATmega1284P the octave can be between 3 and 6.

So to play middle C, C4, on pin 3 use:

(note 3 0 4)

To stop the note playing call note with no arguments:

(note)

The note number can be greater than 11 as an alternative way of representing notes in higher octaves. For example, the following function scale plays the scale of C on pin 3:

(defun scale () 
  (mapc 
   (lambda (n) (note 3 n 4) (delay 500))
   '(0 2 4 5 7 9 11 12)) 
  (note))

The following function wow uses the voltage on analogue input A0 to change the note:

(defun wow () (loop (let ((x (analogread 0))) (note 3 (/ x 22) 3))))

nothing symbol

Syntax: nothing

A symbol with no value. It is useful if you want to suppress printing the result of evaluating a function.

It is equivalent to (values) in Common Lisp.

nth function

Syntax: (nth number list)

Returns the nth item in a list, counting from zero.

Example:

> (nth 2 '(a b c d))
c

You could use nth to write a function end which returns the last item in a list:

(defun end (lis)
  (nth (- (length lis) 1) lis))

For example:

> (end '(a b c d))
d

null function

Syntax: (null item)

Returns t if its argument is nil, or nil otherwise. Equivalent to not.

numberp function

Syntax: (numberp item)

Returns t if its argument is a number.

Example:

> (numberp 'b)
nil

> (numberp (+ 1 2))
t

oddp function

Syntax: (oddp number)

Returns t if the argument is odd, or nil otherwise.

or special form

Syntax: (or item*)

Evaluates its arguments until one returns non-nil, and returns its value.

pinmode Arduino function

Syntax: (pinmode pin mode)

Sets the input/output mode of an Arduino pin number, and returns nil. The mode parameter can be an integer, a keyword, or t or nil:

Keyword Description
:input or nil Input
:output or t Output
:input-pullup Input with pullup resistor
:input-pulldown Input with pulldown resistor *

* ARM processors only.

plusp function

Syntax: (plusp number)

Returns t if the argument is greater than zero, or nil otherwise. Note that (plusp 0) is nil.

pop special form

Syntax: (pop place)

Modifies the value of place, which should be a list, to remove its first item, and returns that item. The second argument place can be one of the forms:

symbol
(car form)
(cdr form
(nth n form)
(aref array index [index*]) 

For more information see setf.

For example:

> (defvar a '(1 2 3 4))
a
> (pop a) 1 > a (2 3 4) 

pprint function

Syntax: (pprint item [stream])

Prints its argument, using the pretty printer, to display it formatted in a structured way. It returns no value. For example, after defining the function var as follows:

(defun var () (loop (let* ((v (analogread 0))) (mapc analogwrite '(10 9 11)
(list (red v) (grn v) (blu v))))))
you could print it formatted using:
> (pprint var)

(lambda nil
  (loop
    (let* ((v (analogread 0)))
      (mapc analogwrite '(10 9 11) (list (red v) (grn v) (blu v))))))

If stream is specified the argument is printed to the specified stream.

pprintall function

Syntax: (pprintall [stream])

Pretty-prints the definition of every function and variable you've defined in the uLisp workspace nicely formatted. The optional stream allows you to print the definitions to a stream

For example, to print a listing of all the currently defined functions and variables to an SD card do:

(with-sd-card (str "Listing.txt" 2)
  (pprintall str))

prin1 function

Syntax: (prin1 item [stream])

Prints its argument, and returns its value. Strings are printed with quotation marks and escape characters; for example:

(prin1 "He said \"hello\"")
would print:
"He said \"hello\""

If stream is specified the argument is printed to the specified stream.

prin1-to-string function

Syntax: (prin1-to-string item [stream])

Prints its argument to a string, and returns the string. Characters and strings are printed with quotation marks and escape characters, in a format that will be suitable for read-from-string. For example:

> (prin1-to-string #\")
"#\\\""

In general,

(read-from-string (princ-to-string 'item))

will give item.

If stream is specified the argument is printed to the specified stream.

princ function

Syntax: (princ item [stream])

Prints its argument, and returns its value. Characters and strings are printed without quotation marks or escape characters; for example:

(princ "He said \"hello\"")
would print:
He said "hello"

If stream is specified the argument is printed to the specified stream.

princ-to-string function

Syntax: (princ-to-string item)

Prints its argument to a string, and returns the string. Characters and strings are printed without quotation marks or escape characters.

For example:

> (concatenate 'string "The result is " (princ-to-string (* 12 34 56)))
"The result is 22848"

print function

Syntax: (print item [stream])

Prints its argument like prin1, but on a new line and followed by a space.

If stream is specified the argument is printed to the specified stream.

progn special form

Syntax: (progn form*)

Evaluates several forms grouped together into a block, and returns the result of evaluating the last form.

push special form

Syntax: (push item place)

Modifies the value of place, which should be a list, to add item onto the front of the list, and returns the new list. The second argument place can be one of the forms:

symbol
(car form)
(cdr form
(nth n form)
(aref array index [index*]) 

For more information see setf.

For example:

> (defvar a '(2 3 4))
a
> (push 1 a) (1 2 3 4) > a (1 2 3 4) 

quote special form

Syntax: (quote item)

Prevents its argument from being evaluated. Can be abbreviated to a single quote mark.

For example:

> '(+ 2 3)
(+ 2 3) 

random function

Syntax: (random number)

Returns a random number between 0 and one less than its argument. For example, to simulate a dice throw:

(+ (random 6) 1)

read function

Syntax: (read [stream])

Reads an atom or list from the specified stream and returns it.

If stream is not specified the item is read from the serial input.

read-byte function

Syntax: (read-byte stream)

Reads a byte from a stream and returns it.

read-from-string function

Syntax: (read-from-string string)

Reads an atom or list from the specified string and returns it.

For example:

> (eval (read-from-string "(* 7 8)"))
56

Any additional characters after the atom or list are ignored; for example:

> (read-from-string "(+ 1 2) (+ 3 4)")
(+ 1 2)

read-line function

Syntax: (read-line [stream])

Reads characters from the serial input up to a newline character, and returns them as a string, excluding the newline.

If stream is specified the line is read from the specified stream.

register function

Syntax: (register address [value])

Reads or writes the value of a peripheral register.

If value is not specified the function returns the value of the register at address.

If value is specified the value is written to the register at address and the function returns value.

For examples on the AVR and ARM versions of uLisp see Programming AVR registers or Programming ARM registers.

require function

Syntax: (require 'symbol)

Loads the definition of a function defined with defun, or a variable defined with defvar, from the Lisp Library. It returns t if it was loaded, or nil if the symbol is already defined, or if the symbol isn't defined in the Lisp Library.

For example, if the Lisp Library is defined in the source file with:

const char LispLibrary[] PROGMEM =
"(defun square (x) (* x x))"
"(defun cube (x) (* x x x))";

then you could load the definition of square into the Lisp workspace using:

(require 'square)

For more information see Lisp Library.

rest function

Syntax: (rest list)

Returns a list with the first item removed.

> (rest '(a b c d e f))
(b c d e f)

Equivalent to cdr.

restart-i2c function

Syntax: (restart-i2c stream [read-p])

Restarts an i2c-stream.

If read-p is nil or omitted the stream is written to.

If read-p is an integer it specifies the number of bytes to be read from the stream.

return special form

Syntax: (return [value])

Exits from a loop, dotimes, or dolist block. Returns value, or nil if no value is specified.

reverse function

Syntax: (reverse list)

Returns a list with the elements of list in reverse order. For example:

> (reverse '(1 2 3 4 5))
(5 4 3 2 1) 

The function reverse is useful if you have been using cons to add elements onto the front of a list, but you want to return the list with the earliest elements at the front. For example, the following function log reads x values on analogue input A0 once a second, and returns the list of values:

(defun log (x)
  (let ((lst nil))
    (dotimes (j x (reverse lst))
      (setq lst (cons (analogread 0) lst))
      (delay 1000))))

If the voltage was slowly rising on A0 you might get:

> (log 10)
(14 16 27 38 49 79 102 134 156 178)

room function

Syntax: (room)

Returns the number of free Lisp cells remaining.

> (room)
280

save-image function

Syntax: (save-image [symbol])

Saves the current uLisp image to non-volatile memory or SD card so it can be loaded using load-image.

Note that saved Lisp images may not be compatible across different releases of uLisp.

Saving to SD card

If you have SD card support enabled, with #define sdcardsupport active, save-image saves to the SD card:

  • To save the image on the SD card as ulisp.img, with no autorun function, give the command:
(save-image)
  • To save the image to the SD card as filename, with no autorun function, give the command:
(save-image filename)
  • To save the image to the SD card as ulisp.img, with (fun) as the autorun function, give the command:
(save-image 'fun)

Saving to EEPROM or DataFlash

If you don't have SD card support enabled, with #define sdcardsupport commented out, save-image saves to EEPROM or DataFlash if these are available:

  • To save the image to EEPROM/DataFlash, with no autorun function, give the command:
(save-image)
  • To save the image to EEPROM/DataFlash, with (fun) as the autorun function, give the command:
(save-image 'fun)

The autorun function will be run if the option #define resetautorun is active.

The save-image command will return the size of the image, in objects. For example, since each object is four bytes, an ATmega328 with 1 Kbytes of EEPROM has room for an image containing 256 objects.

If there isn't enough EEPROM space to save the image, the following error will be displayed;

Error: Image size too large: 258

You should then free some space with makunbound, and try again.

search function

Syntax: (search pattern target)

Returns the index of the first occurrence of pattern in target, which can be lists or strings, or nil if it's not found.

Not available in the AVR-Nano version of uLisp.

For example:

> (search "cat" "the cat sat on the mat"))
4
> (search '(5 9) '(3 1 4 1 5 9 2 6))
4

second function

Syntax: (second list)

Returns the second item in a list. 

> (second '(a b c d e f))
b

A more memorable name for cadr.

set function

Syntax: (set symbol value [symbol value]*)

Assigns the value of the second argument to the value of the first argument:

> (set 'a (+ 1 2 3))
6

setf special form

Syntax: (setf place value [place value]*)

Modifies an existing list by setting the position in the list specified by place to the result of evaluating value. The second argument place can be one of the forms:

symbol
(car form)
(cdr form
(nth n form)
(aref array index [index*]) 

first and rest can also be used as synonyms for car and cdr.

The following examples illustrate each of these options.

variable

(setf symbol value)

This is equivalent to:

(setq symbol value)

car

(setf (car form) value)

Replaces the car of the value of form with value. For example:

> (defvar a '(b c))
a

> (setf (car a) 'e)
e

> a
(e c) 

cdr

(setf (cdr form) value)

Replaces the cdr of the value of form with value. This is particularly useful in conjunction with assoc, to change the value associated with a key in an association list. For example:

> (defvar col '((red . 23) (blu . 34) (grn . 45)))
col

> (setf (cdr (assoc 'grn col)) 100)
100

> col
((red . 23) (blu . 34) (grn . 100))

nth

(setf (nth n form) value)

Replaces the nth value of the list form with value. This allows you to use a list of items as an array, accessed by the index of each item. The following example uses xyz as an array of coordinates in three dimensions:

> (defvar xyz '(0 0 0))
xyz

> (setf (nth 0 xyz) 90)
90

> (setf (nth 1 xyz) 45)
45

> xyz
(90 45 0)

aref

(setf (aref array index [index*]) value)

Replaces the value of the specified element in array a with value. For example:

> (defvar a (make-array '(2 3)))
a

> a
#2A((nil nil nil) (nil nil nil))

> (setf (aref a 1 2) 90)
90

> a
#2A((nil nil nil) (nil nil 90))

setq special form

Syntax: (setq symbol value [symbol value]*)

Assigns the value of the second argument to the variable specified in the first argument:

> (setq a (+ 1 2 3))
6

You can make several assignments in a single setq:

> (setq a (+ 2 3) b (+ 4 5))
9

sleep function

Syntax: (sleep seconds)

Puts the processor into a low-power sleep mode for approximately the specified number of seconds. During sleep the current consumption typically drops to 50 µA on ATmega processors.

sort function

Syntax: (sort list test)

Sorts the list according to the test function, and returns the sorted list. Note that for efficiency the sort is destructive, meaning that the value of list may be changed by the operation.

For example:

>  (sort '(3 1 4 1 5 9) <)
(1 1 3 4 5 9)
>  (sort '("dog" "cat" "ant" "eel" "owl" "mouse") string<)
("ant" "cat" "dog" "eel" "mouse" "owl")

The test function could be a lambda expression; for example, to sort strings into ascending order of length:

> (sort '("giraffe" "lion" "ape" "rhino") (lambda (x y) (< (length x) (length y))))
("ape" "lion" "rhino" "giraffe")

streamp function

Syntax: (streamp item)

Returns t if the argument is a valid stream and nil otherwise.

string function

Syntax: (string item)

Converts its argument, which should be a character or a symbol, to a string.

For example:

> (string #\*)
"*"

> (string 'cons)
"cons"

string< function

Syntax: (string< string string)

Returns t if the first string is alphabetically less than the second string, and nil otherwise. For example:

> (string< "cat" "cats")
t

string= function

Syntax: (string= string string)

Tests whether two strings are the same.

string> function

Syntax: (string> string string)

Returns t if the first string is alphabetically greater than the second string, and nil otherwise. For example:

> (string> "mouse" "mice")
t

stringp function

Syntax: (stringp item)

Returns t if the argument is a string and nil otherwise.

subseq function

Syntax: (subseq string start [end])

Returns a subsequence of a list or string.

Lists

Returns a new list consisting of item start to item end-1:

> (subseq '(0 1 2 3 4 5) 2 4)
(2 3)

If the third argument is omitted subseq returns from start to the end of the string:

> (subseq '(0 1 2 3 4 5) 2)
(2 3 4 5)

Strings

Returns a new string consisting of character start to character end-1:

> (subseq "hello" 0 3)
"hel"

If the third argument is omitted subseq returns from start to the end of the string:

> (subseq "hello" 3)
"lo"

The following example day returns a three-letter day string for the day number 0 to 6:

(defun day (d)
  (subseq "MonTueWedThuFriSatSun" (* 3 d) (* 3 (1+ d))))

symbolp function

Syntax: (symbolp item)

Returns t if the argument is a symbol and nil otherwise.

symbol

Syntax: t

A symbol representing true.

terpri function

Syntax: (terpri [stream])

Prints a new line, and returns nil.

If stream is specified the new line is written to the specified stream. 

third function

Syntax: (third list)

Returns the third item in a list. 

> (third '(a b c d e f))
c

A more memorable name for caddr.

time special form

Syntax: (time form)

Prints the value returned by the form, and the time taken to evaluate the form in milliseconds or seconds.

For example:

> (time (tak 18 12 6))
7
Time: 56.1 s

trace special form

Syntax: (trace [function]*)

Turns on tracing of up to three user-defined functions. It returns a list of the functions currently being traced; for example:

> (trace fac)
(fac sq)

Giving (trace) with no arguments returns a list of the functions currently being traced.

Tracing a function prints out the call depth, and a list of the arguments each time the function is called, and the call depth and result each time the function returns.

For example, if you defined:

(defun fac (n)
  (if (= n 1) 1
    (* n (fac (- n 1)))))

you can turn on tracing of fac by typing:

> (trace fac)

Calling fac as follows:

> (fac 4)

will print this trace output:

0: (fac 4)
  1: (fac 3)
    2: (fac 2)
      3: (fac 1)
      3: fac returned 1
    2: fac returned 2
  1: fac returned 6
0: fac returned 24
24

Note that trace will not show calls to functions supplied as an argument to another function, such as apply, funcall, mapc, or mapcar, because in these cases only the body of the function is passed. For example:

(defun sq (x) (* x x))
(trace sq)
(mapcar sq '(1 2 3))

The solution is to wrap the function call in a lambda:

(mapcar (lambda (x) (sq x)) '(1 2 3))

unless special form

Syntax: (unless test form*)

Evaluates the test. If it's nil the forms are evaluated and the last value is returned.

For example:

> (unless (digitalread 3) (digitalwrite 4 t))

This reads input D3. If it's low the LED on D4 is lit.

untrace special form

Syntax: (untrace [function]*)

Turns off tracing of the specified user-defined functions.

To turn off tracing for all functions type:

> (untrace)

This returns a list of the functions that have been untraced.

unwind-protect special form

Syntax: (unwind-protect form1 [forms]*)

Evaluates form1 and forms in order and returns the value of form1, but guarantees to evaluate forms even if an error occurs in form1.

For example, the standard blink program can leave the LED on if you escape. You can solve this with unwind-protect:

(defun blink ()
  (pinmode :led-builtin t)
  (unwind-protect
      (loop
       (digitalwrite :led-builtin (not (digitalread :led-builtin)))
       (delay 1000))
    (digitalwrite :led-builtin nil)))

Now the LED will always be turned off when you escape by typing ~.

when special form

Syntax: (when test form*)

Evaluates the test. If it's non-nil the forms are evaluated and the last value is returned.

For example:

> (when (digitalread 3) (digitalwrite 4 t))

This reads input D3. If it's high the LED on D4 is lit.

with-i2c special form

Syntax: (with-i2c (stream [port] address [read-p]form*)

Evaluates the forms with stream bound to an i2c-stream defined by address.

On processors that support two I2C ports port can be 0 or 1 to specify the port. If omitted it defaults to 0.

For details of the available pins see the appropriate board description on this site.

If read-p is nil or omitted the stream is written to.

If read-p is an integer it specifies the number of bytes to be read from the stream.

The stream is bound to an i2c-stream:

> (with-i2c (str #x70) str)
<i2c-stream #x70>

The AVR version of uLisp uses my own I2C routines which don't need a buffer, and don't impose any limit on the length of transactions. The ARM, ESP, and MSP430 versions of uLisp use the Arduino Wire library, which imposes a 32-byte limit on each transaction.

Port scanner

If the start operation fails the stream variable is bound to nil:

> (with-i2c (str #x71) str)
nil

This allows you to write a very simple port scanner to find all the I2C devices on the bus:

(defun scn () 
  (dotimes (p 127)
    (with-i2c (str p)
      (when str (print p)))))

with-output-to-string special form

Syntax: (with-output-to-string (streamform*)

Returns a string containing the output to the specified stream variable.

For example:

> (with-output-to-string (str) (princ "The result is: " str) (princ 24 str))
"The result is: 24"

uLisp only supports outputting to one string at a time from with-output-to-string or princ-to-string.

with-sd-card Arduino function

Syntax: (with-sd-card (stream filename [mode]) form*)

Evaluates the forms with stream bound to an sd-stream reading from or writing to the file filename.

The filename should be a string of up to 12 characters, consisting of a filename of up to 8 characters, a dot, and an extension of up to three characters.

The mode argument specifies whether the file is opened for reading or writing:

Mode Effect
0 or nil Read
1 Write-Append
2 Write-Overwrite

If the file already exists Append writes to the end of the file without affecting the existing contents, whereas Overwrite deletes any existing content first.

For example, the following command writes the string "Hello" to the SD card file "Greeting.txt":

(with-sd-card (str "Greeting.txt" 2)
  (print "Hello" str))

and the following command reads it back:

(with-sd-card (str "Greeting.txt")
  (read str))

Writing to an SD card

The functions print, prin1, princ, terpripprint, write-byte, write-string, and write-line can all be used to write to an SD card.

Reading from an SD card

The functions read, read-byte, and read-line can all be used to read from an SD card. If the end of the file has been reached, each of these functions returns nil.

with-serial special form

Syntax: (with-serial (stream port [baud]form*)

Evaluates the forms with stream bound to a serial-stream using serial port port.

For details of the available pins see the appropriate board description on this site.

By default the baud rate is 9600. You can specify the following baud rates by specifying the third baud parameter as one of the following values:

3, 6, 12, 24, 48, 96, 144, 192, 288, 384, 576, or 1152.

Note that the baud rate is the baud parameter times 100; for example, for 38400 baud specify 384.

For example, if you define:

(defun listen ()
  (with-serial (str 1 96)
    (loop
     (print (read-line str)))))

and then connect the Port 1 RX pin to the TX pin of a GPS module, running the listen program by typing:

(listen)

will display output from the GPS module; for example:

"$GPRMC,183534.000,A,5213.1091,N,00008.2271,E,0.39,248.14,201117,,,A*61
"$GPVTG,248.14,T,,M,0.39,N,0.72,K,A*39

with-spi special form

Syntax: (with-spi (stream pin [clock] [bitorder] [mode] [port]form*)

Evaluates the forms with stream bound to an spi-stream. The parameters are:

  • stream: a variable that will be bound to an spi-stream. The variable should be specified in commands to read from and write to the stream within the form.
  • pin: the enable pin.
  • clock: the frequency of the SPI clock, in kHz. It defaults to 4000, a 4 MHz clock.
  • bitorder: the bit order, 0 for LSBFIRST, or 1 for MSBFIRST. It defaults to MSBFIRST.
  • mode: the SPI mode, 0 to 3. It defaults to mode 0.
  • port: the SPI port, 0 or 1. It defaults to 0.

For example, to write a byte #xAA using pin 10 as the enable pin, a 4 MHz clock, MSB first, and mode 0, you would specify:

(with-spi (str 10 4000 1 0)
  (write-byte #xAA str))

You would get the same settings if you wrote:

(with-spi (str 10)
  (write-byte #xAA str))

For details of the available pins see the appropriate board description on this site.

The SPI interface will use the fastest available clock rate that is less than or equal to the specified value of clock.

write-byte function

Syntax: (write-byte number [stream])

Writes a byte to a stream.

write-line function

Syntax: (write-line string [stream])

Writes a string terminated by a newline character. If stream is specified the string is written to the stream.

write-string function

Syntax: (write-string string [stream])

Writes a string. If stream is specified the string is written to the stream.

zerop function

Syntax: (zerop number)

Returns t if the argument is zero, or nil otherwise.