Variables

The uLisp equivalent of the Arduino Blink program is:

(defun b ()
  (pinmode 13 t)
  (loop
   (digitalwrite 13 t)
   (delay 1000)
   (digitalwrite 13 nil) 
   (delay 1000)))

We can run this by typing:

> (b)

Local variables

We have already seen how we can pass parameters to a function. So we could make a version of the blink function with the delay as a parameter, so we can vary the blink rate:

(defun b (del)
  (pinmode 13 t)
  (loop
   (digitalwrite 13 t)
   (delay del)
   (digitalwrite 13 nil) 
   (delay del)))

Now we can create a faster blink by typing, for example:

> (b 200)

In the definition of b, the symbol del is a variable. It's like a box into which we put any value we want to pass to the function.

Furthermore, it's called a local variable because the value is only available inside the body of the function. If we try and evaluate del outside the function we get:

> del
Error: 'del' undefined

Defining a global variable: defvar

To avoid the need to remember which pin the LED is connected to we can define a variable called led:

(defvar led 13)

Now we can refer to the LED pin using the variable led:

(defun b (del)
  (pinmode led t)
  (loop
   (digitalwrite led t)
   (delay del)
   (digitalwrite led nil) 
   (delay del)))

Variables defined by defvar are called global variables because you can refer to them anywhere.

> led
13

Changing the value of a variable: setq

To change the value of a variable we can use setq. For example, if we want to blink an LED on pin 4:

(setq led 4)

Now the Blink procedure b will automatically blink the new LED.

You can also use setq in a function to change a local variable.

Creating local variables: let

The let construct allows you to define one or more variables, with specified initial values, which are local to the body of the let construct. It is written like this:

(let* ((var1 value1)
       (var2 value2)
       ...)
  body)

where:

  • var1 is the first local variable and value1 is its initial value.
  • var2 is the second local variable and value2 is its initial value, and so on.
  • body is one or more Lisp functions that can refer to var1 and var2.

As an example of its use, remember our definition of the average function:

(defun ave (n1 n2)
(/ (+ n1 n2) 2))

The parameters n1 and n2 are local variables, local to the body of the function.

But suppose we wanted to break the calculation into steps, using a local variable sum to store the sum of the two numbers.

We could do this with let:

(defun ave (n1 n2)
  (let ((sum (+ n1 n2)))
    (/ sum 2))

This would be especially useful if we wanted to use the sum in several places in the function.

Exercises

1. Find the average of three numbers

Define a procedure av3 that finds the average of three numbers.

Check that:

(av3 21 7 8)

gives 12.

2. Cube the sum of two numbers

Here's a procedure cs that calculates (a + b) x (a + b) x (a + b):

(defun cs (a b)
  (* (+ a b) (+ a b) (+ a b)))

Use let to write it so (a + b) is only calculated once.

Check that:

(cs 3 4)

gives 343.

3. Substitute values into a quadratic equation

Write a procedure pp (pseudo-primes) that substitutes x into the quadratic equation:

x2 - x + 41

Check that:

(pp 40)

gives 1601.