Chapter 2
Lists
A program is a list of words, and so is everything a program keeps for later. This chapter is about making lists, taking them apart, and running them.
Writing a list
{ starts a list and } ends it. Everything between
them is collected as it is, without running:
{ a b c }
values: ( ( "a" "b" "c" ) )
The list's first word is its top, and lists print top first, just like the values stack. Lists can hold lists:
{ a { b c } d }
values: ( ( "a" ( "b" "c" ) "d" ) )
The words inside are not run, and that includes #:
{ # 1 } is a list of two words, # and
1, not a list holding the number 1.
{ # 1 } size debug
2 values: ( )
Running a list
call takes a list off the values stack and puts its words on the
instructions stack, so they run next. A list in braces is a piece of program
you can keep, pass around and run later.
# 5 { dup * } call debug
25 values: ( )
Collecting values
[ and ] are the other way to make a list: the words
between them do run, and whatever they leave on the values stack becomes
the list.
[ # 1 # 2 # 3 # 4 + ]
values: ( ( 1 2 7 ) )
Compare { # 1 # 2 }, a list of four words, with
[ # 1 # 2 ], a list of two numbers. [ marks the values
stack and ] takes everything pushed since the mark, so values
already on the stack before the [ are left alone. The first value
pushed inside the brackets becomes the list's top, so the list reads in the
order you wrote it:
before [ first second ]
values: ( ( "first" "second" ) "before" )
Taking lists apart
Stacks are written top first, as in chapter 1:
| word | takes | leaves |
|---|---|---|
size | ( list ) | ( n ), how many elements |
peek | ( list ) | ( first ) |
pop | ( list ) | ( first rest ) |
push | ( list v ) | ( list′ ), the list with v first |
reversed | ( list ) | ( list′ ), backwards |
append | ( b a ) | ( list′ ), the elements of a and then of b |
{ a b } { c d } append
values: ( ( "a" "b" "c" "d" ) )
{ a b c } pop debug debug
a ( "b" "c" ) values: ( )
pop leaves the rest of the list below the element it took, so the
first debug prints a and the second prints what was
left. push wants the value first and the list on top:
x { a b } push
values: ( ( "x" "a" "b" ) )
If the list is already on the stack and the value arrives after it, use
swap first:
{ a b } x swap push
values: ( ( "x" "a" "b" ) )
Frozen and thawed
Every Ether object is either frozen, which means it never changes, or
thawed, which means it can. A list in braces is a frozen list, called a
tuple. stack makes a new, empty thawed list, called a
stack. inspect shows what an object is without
removing it.
{ a b } inspect del
stack inspect del
tuple frozen ( "a" "b" ) stack thawed clean cold serial 6 ( ) values: ( )
inspect prints the kind of object first (tuple or stack), then
frozen or thawed. For thawed objects it adds three more things you can ignore
for now: clean or dirty (whether it holds any thawed
list or table), cold or warm (whether it holds any
thawed object at all), and its serial, a number the process gives
each thawed object it makes, in order.
Pushing onto a tuple never changes it: push gives back a new
tuple and the old one is still there. Pushing onto a stack changes that
stack, and every reference to it sees the change; push then gives
back the same stack. Here dup makes
a second reference to the same list before the push, and the push's result is
thrown away with del:
{ a } dup x swap push del debug
stack dup x swap push del debug
( "a" ) ( "x" ) values: ( )
The tuple is unchanged; the stack now holds x. Most of the
time, frozen objects are the safer choice: nothing can change them behind your
back, and they can be shared freely, even between processes. freeze
makes a frozen copy of a thawed object, and clone makes a new,
separate one.
stack x swap push freeze inspect
tuple frozen ( "x" ) values: ( ( "x" ) )
Exercise 2.1
Make a list of the numbers 10, 20 and 30, in that order from the top, and print its size.
A correct answer prints:
3 values: ( )
One answer
[ # 30 # 20 # 10 ] size debug
3 values: ( )
Exercise 2.2
Run the program { # 1 + } three times on the number 5, then
print the result. Write the list only once: keep it on the values stack and
use dup, swap and swap2 to have a copy
on top, with the number under it, each time you call. Any other
word from chapters 1 and 2 is allowed too. Writing the stack down after each
word, top first, helps.
A correct answer prints:
8 values: ( )
One answer
# 5 { # 1 + } dup swap2 swap call swap dup swap2 swap call swap call debug
8 values: ( )
Exercise 2.3
Starting from { red green blue }, print red and
then leave the list ( "green" "blue" ) on the values stack.
A correct answer prints:
red values: ( ( "green" "blue" ) )
One answer
{ red green blue } pop debug
red values: ( ( "green" "blue" ) )
Exercise 2.4
Make a stack, push red and then blue onto it,
freeze it, and inspect the result.
A correct answer prints:
tuple frozen ( "blue" "red" ) values: ( ( "blue" "red" ) )
One answer
stack red swap push blue swap push freeze inspect
tuple frozen ( "blue" "red" ) values: ( ( "blue" "red" ) )