3.3.
Lists, Lists And More Lists
We've trained you in variables and functions, and now enter the
murky swamps of Scheme's lists.
Before we talk more about lists, it is necessary that you know
the difference between atomic values and lists.
You've already seen atomic values when we initialized
variables in the previous lesson. An atomic value is a single
value. So, for example, we can assign the variable "x" the
single value of 8 in the following statement:
(let* ( (x 8) ) x)
(We added the expression x
at the end to print out the value
assigned to x
-- normally you won't need to do this. Notice how
let*
operates just like a function: The value of
the last statement is the value returned.)
A variable may also refer to a list of values, rather than a
single value. To assign the variable x
the
list of values 1, 3, 5, we'd type:
(let* ( (x '(1 3 5))) x)
Try typing both statements into the Script-Fu Console and
notice how it replies. When you type the first statement in,
it simply replies with the result:
8
However, when you type in the other statement, it replies with
the following result:
(1 3 5)
When it replies with the value 8 it is informing you that
x
contains the atomic value 8. However,
when it replies with (1 3 5), it is then informing you that
x
contains not a single value, but a list
of values. Notice that there are no commas in our declaration
or assignment of the list, nor in the printed result.
The syntax to define a list is:
'(a b c)
where a
, b
, and
c
are literals. We use the apostrophe (')
to indicate that what follows in the parentheses is a list of
literal values, rather than a function or expression.
An empty list can be defined as such:
'()
or simply:
()
Lists can contain atomic values, as well as other lists:
(let*
(
(x
'("The Gimp" (1 2 3) ("is" ("great" () ) ) )
)
)
x
)
Notice that after the first apostrophe, you no longer need to
use an apostrophe when defining the inner lists. Go ahead and
copy the statement into the Script-Fu Console and see what it
returns.
You should notice that the result returned is not a list of
single, atomic values; rather, it is a list of a literal ("The
Gimp")
, the list (1 2 3)
, etc.
3.3.2. How To Think Of Lists
It's useful to think of lists as composed of a "head" and a
"tail." The head is the first element of the list, the tail
the rest of the list. You'll see why this is important when we
discuss how to add to lists and how to access elements in the
list.
3.3.3. Creating Lists Through Concatenation (The Cons Function)
One of the more common functions you'll encounter is the cons
function. It takes a value and prepends it to its second
argument, a list. From the previous section, I suggested that
you think of a list as being composed of an element (the head)
and the remainder of the list (the tail). This is exactly how
cons functions -- it adds an element to the head of a
list. Thus, you could create a list as follows:
(cons 1 '(2 3 4) )
The result is the list (1 2 3 4)
.
You could also create a list with one element:
(cons 1 () )
You can use previously declared variables in place of any
literals, as you would expect.
3.3.4. Defining A List Using The list Function
To define a list composed of literals or previously declared
variables, use the list function:
(list 5 4 3 a b c)
This will compose and return a list containing the values held
by the variables a
, b
and c
. For example:
(let* (
(a 1)
(b 2)
(c 3)
)
(list 5 4 3 a b c)
)
This code creates the list (5 4 3 1 2 3)
.
3.3.5. Accessing Values In A List
To access the values in a list, use the functions car
and cdr
,
which return the first element of the list and the rest of the
list, respectively. These functions break the list down into
the head::tail construct I mentioned earlier.
car
returns the first element of the list (the
head of the list). The list needs to be non-null. Thus, the
following returns the first element of the list:
(car '("first" 2 "third"))
which is:
"first"
cdr
returns the rest of the list after the first
element (the tail of the list). If there is only one element
in the list, it returns an empty list.
(cdr '("first" 2 "third"))
returns:
(2 "third")
whereas the following:
(cdr '("one and only"))
returns:
()
3.3.8. Accessing Other Elements In A List
OK, great, we can get the first element in a list, as well as
the rest of the list, but how do we access the second, third
or other elements of a list? There exist several "convenience"
functions to access, for example, the head of the head of the
tail of a list (caadr
), the tail of the tail of a
list (cddr
), etc.
The basic naming convention is easy: The a's and d's represent
the heads and tails of lists, so
(car (cdr (car x) ) )
could be written as:
(cadar x)
To view a full list of the list functions, refer to the
Appendix, which lists the available functions for the version
of Scheme used by Script-Fu.
To get some practice with list-accessing functions, try typing
in the following (except all on one line if you're using the
console); use different variations of car and cdr to access
the different elements of the list:
(let* (
(x '( (1 2 (3 4 5) 6) 7 8 (9 10) )
)
)
; place your car/cdr code here
)
Try accessing the number 3 in the list using only two function
calls. If you can do that, you're on your way to becoming a
Script-Fu Master!
|
Note |
In Scheme, a semicolon (";") marks a comment. It, and
anything that follows it on the same line, are ignored by the
script interpreter, so you can use this to add comments to jog
your memory when you look at the script later.
|