PicoLisp Explored: The SET function
Mia
Posted on November 21, 2021
In this series, we will further explore functions and concepts of PicoLisp that have not been covered in the beginner's tutorial.
Today we will talk about the set
function. Although its purpose is simple (setting values to variables), the usage can be confusing if you are not aware of the internal data representation in PicoLisp. So let's go through it and try to understand what is going on.
Some knowledge of the internal representation of data will be helpful, so consider to read the article about concepts and data types first if you haven't done so.
The set
function
From the docs:
(set 'var 'any ..) -> any
Stores new values
any
in thevar
arguments.
Examples:
: (set 'L '(A B C) (cdr L) 999)
-> 999
: L
-> (A 999 C)
Teaser: Playing around in the REPL
Let's take a look at the example: First we set (A B C)
to the L
symbol, and then we write 999 in its cdr
. We know that (cdr L)
is (B C)
.
Question: ** *Why do we get (A 999 C)
as result, and **not (A 999)
(as one might expect)?*
Let's define L
as (A B C)
and then set L
to 999
.
:(setq L '(A B C))
-> (A B C)
: (set L 999)
-> 999
What do you expect as result?
: L
-> (999 B C)
Only the first item in the list L
is changed. Now the cdr
:
:(cdr L)
-> (B C)
:(set (cdr L) 888)
-> 888
Again, what do you expect? This is the result:
: L
-> (999 888 C)
Only the first item of the cdr
is changed.
Now let's see what happens if we modify the car
of a list of symbols: '(A B C)
.
:(setq L '(A B C))
-> (A B C)
:(set (car L) 999)
-> 999
: L
-> (A B C)
The first item of L
is still A
! Why? Because the symbol A
has changed, not L
:
: A
-> 999
Obviously, there is a difference between (set (car L) 999)
and (set L 999)
. But what exactly is different?
Maybe you already see the point. In any case, let's go back to the basics to really understand what is happening here.
Concepts and Data Types revisited
We remember: PicoLisp consists only of "cells" where each cell has a CAR and a CDR.
+-----+-----+
| CAR | CDR |
+-----+-----+
A symbol
has a value VAL, which is in the CDR of the symbol. The pointer to the symbol points at the CDR part of the cell.
Symbol
|
V
+-----+-----+
| / | VAL |
+-----+-----+
Now let's have a look at lists. Lists are constructs that have the value in the CAR and a pointer to the next cell in the CDR.
|
V
+-----+-----+
| any | | |
+-----+--+--+
|
V
+-----+-----+
| any | | |
+-----+--+--+
|
V
...
The important thing to understand is that set
takes the new value and writes it to the "position of the arrow".
Visualizing the cells
It is easier to understand if we directly see the cell structure. Let's re-visit the very first example.
:(setq L '(A B C))
: (set L 999)
: L
-> (999 B C)
L is a list, which means that the pointer points at the CAR. So what is actually set, is this:
The rest of the list is the same, especially the pointers to the next cell.
Now back to the second example, where we set
a new value to (cdr L)
. (cdr L)
is also a list, where its first element is B
. B
actually is a symbol which is stored in its own cell, so the car
of the first list contains a pointer to the B
cells. So if we now execute:
:(set (cdr L) 888)
-> 888
then the pointer to the B
-cell is overwritten by 888
. Again, the pointer to the next cell is unchanged:
Now let's revisit the third example from above:
:(setq A 7 B 2 C 3)
-> 7
:(setq L '(A B C))
-> (A B C)
The items(A B C)
are each symbols which have some value assigned. Their value is not directly stored in the cell (as would be the case for numbers), but in a separate cell. This means that (car L)
actually contains a pointer to the symbol A
.
Let's consider a symbol A
with value 7. Then the cells will look like this:
|
V
+-----+-----+
A | | | 7 |
+--+--+-----+
|
V
+-----+-----+
| | | 65 | ASCII "A" = 65
+--+--+-----+
The pointer from the list is pointing to the CDR, which contains the value of A
. Now let's execute:
:(set (car L) 111)
-> 111
Which value are we actually setting? Well, this one:
Since we only change the value of A
, the structure of L
and A
remain unchanged. L
still points to A
, only that it now has a different value.
What happens if we try to do (set (car L) 111)
if the first item of L
is not a symbol?
:(setq L '(1 2 3)
!? (set (car L) 111)
1 -- Variable expected
We get an error becaus integers are stored directly in the cell. Therefore there is nocar
which could be addressed.
Wrap-up
As you can see, even a simple function such as set
is much easier to understand with some knowledge of the internal cell representation in PicoLisp.
We will see many examples of the usage of set
in the Rosetta Code examples as it is a widely used function, for example in the next post about the 100 Doors riddle.
Sources:
Posted on November 21, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.