Processing items in a list
Lists provide a useful way of representing collections of data, such as the notes in a tune, or the sequence of analogue values read from an input. This section introduces two very useful functions for processing items in a list.
Processing the items in a list - mapc
The function mapc performs a function on each item in a list. For example:
> (mapc print '(0 1 2 3)) 0 1 2 3 nil
Here's a more interesting example. The following list represents the notes of a familiar tune:
(defvar tun '(0 0 7 7 9 9 7 nil 5 5 4 4 2 2 0))
We've used nil to insert a gap. The following function pla plays a single note, or a gap if its argument is nil:
(defun pla (x) (when x (note 3 x 4)) (delay 200) (note) (delay 200))
We can use mapc to apply the function to each of the items in the tune. The first argument is a function, and the second argument is the list we want to process:
(mapc pla tun)
Connect a piezo speaker between pin 3 and GND on an Arduino Uno to hear the tune.
Alternatively, on an Arduino Mega 2560 connect the piezo speaker between pin 9 and GND and change the definition of pla to:
(defun pla (x) (when x (note 9 x 4)) (delay 200) (note) (delay 200))
Transforming a list - mapcar
The related function mapcar applies a specified function to each of the items in a list, but it then returns the list of results. For example:
> (mapcar 1+ '(0 1 2 3 4)) (1 2 3 4 5)
(defun inv (x) (when x (- 12 x)))
> (mapcar inv tun) (12 12 5 5 3 3 5 nil 7 7 8 8 10 10 12)
or we can play the inverted tune with:
(mapc pla (mapcar inv tun)
Both mapc and mapcar can alternatively take a function of two arguments, and two lists, and apply the function to corresponding elements of both lists until the shortest list runs out. For example:
> (mapcar * '(1 2 3) '(4 5 6)) (4 10 18)
You can alternatively specify the function using a lambda expression. For example, to square each item in a list:
> (mapcar (lambda (x) (* x x)) '(1 2 3 4 5)) (1 4 9 16 25)