A sequence is a generalized array or list:
Zero or more values treated as a compound value.
Sequences have certain common operations, including indexing and iteration.
(Technical note: Sequences generally implement the java.util.List
interface, but Kawa will also treat strings and native
Java arrays as sequences.)
In traditional Lisp-family languages, the list is the
most important kind of sequence.
(Don’t confuse Java’s List
interface with Kawa’s use of the
word list. They’re related, in that a Kawa “list” implements
the List
interface, so any list is also List
,
but not vice versa.)
A list is implemented as a chain of linked pairs. You can create a constant list by quoting a parenthesized list:
'(3 4 (10 20 30) "a string")
See Lists for details and operations.
A vector is a sequence that is implemented by storing the elements side-by-side in memory. A vector uses less space than a list of the same length, and is generally more efficient than a list.
To create a vector you can use a bracketed list:
(! vec1 ['A 'B 'C 'D 'E 'F])
This creates a vector of 6 symbols and binds it to vec1
.
To select an element you can use the traditional
vector-ref
procedure:
(vector-ref vec1 3) ⇒ 'D
Alternatively, in Kawa you can use function-call notation:
(vec1 3) ⇒ 'D
You can also create a vector using the traditional vector
constructor:
(! vec2 (vector 'A 'B 'C 'D 'E 'F))
There is one important difference between vec1
and vec2
:
You can modify vec2
by changing some or all of its elements.
You can’t do that for vec1
.
(We say that vec1
is an immutable or constant vector,
while vec1
is a mutable or modifiable vector.)
To change an element use either the traditional vector-set!
procedure, or function-call notation:
(vector-set! vec2 2 'Y)
(set! (vec2 4) 'Z)
vec2 ⇒ ['A 'B 'Y 'D 'Z 'F]
(vector-set! vec1 2 'Y) ⇒ throws exception
See Vectors for details and operations.
See Using Java arrays for examples.
You can use function-call notation to index a generalized sequence,
whether it is a list, vector, any java.util.List
,
native Java array, or string:
((list 'A 'B 'C 'D) 2) ⇒ 'C ("abcdef" 3) ⇒ ⇒ (! farr (float[] 1.5 3 4.5)) ;; native Java array (farr 2) ⇒ 4.5
Note that indexing a list with an index i
will be slow, since it
has to step through the list i
times. (So don’t do that!)
A range is a sequence of numbers in order, spaced uniformly apart. Usually, these are (exact) integers that increase by one. The usual notation is:
[start
<:end
]
This is the sequence of integers starting with the integer start
(inclusive) and ending with the integer end
(exclusive).
For example [3 <: 7]
is the sequence [3 4 5 6]
.
The ‘<:
’ is a keyword; the <
is a mnemonic for the
set of integers that are <
the end value 6.
You can also use <=:
if you want to include the upper bound:
[4 <=: 8]
is [4 5 6 7 8]
.
You can use >=:
or >:
for a decreasing range.
[5 >=: 1]
or [5 >: 0]
both evaluate to [5 4 3 2 1]
.
You can also specifify a step value: [1 by: 2 <=: 9]
,
which evaluates to [1 3 5 7 9]
.
(Details here.)
If an index is a sequence of integers, the result is a new sequence (of the same type) selecting only the elements matching the index values. For example:
#|kawa:2|# (vec1 [3 5 2])
#(D F C)
In general, ((V1 V2) I)
is (V1 (V2 I))
.
You can use a range to create a slice - a contiguous subset of a list.
#|kawa:3|# (vec1 [2 <: 6])
#(C D E F)
A range is different from a vector integer in that you can use a range as the index in the LHS of a set!:
#|kawa:4|#(set! (vec1 [2 <: 4]) #(a b c d e))
#|kawa:5|#vec1
#(A B a b c d e E F)
Notice how the number of replaced elements can be different then the number of elements in the replacement value. I.e. you can do insertion and deletion this way.
#|kawa:7|#(! str1 (string-copy "ABCDEF"))
#|kawa:8|#(set! (str1 [2 <: 5]) "98")
AB98F