Arrays are ordered and homogeneous. Indexing is zero-based; negative indices count from the end:
1 2 3 4 5 6 7
nums = [10, 20, 30]
log[nums[0]]
log[nums[-1]]
log[len[nums]]
more = push[nums, 40]
log[more]
log[concat[[1, 2], [3, 4]]]expected output — from the book, verified by crow test --book
10
30
3
[10, 20, 30, 40]
[1, 2, 3, 4]push and concat return new arrays — Crow collections are
immutable-by-rebuild, which is part of what keeps parallel loops safe.
An all-numeric array literal is backed by a real tensor, so math works on
it wholesale — + adds element-wise against another tensor or broadcasts
a scalar; the dotted operators .*, ./, .^ are explicit element-wise
multiply/divide/power:
1 2 3 4 5
a = [1.0, 2.0, 3.0]
b = [10.0, 20.0, 30.0]
log[a .* b]
log[a + b]
log[a * 2.0]expected output — from the book, verified by crow test --book
[10, 40, 90]
[11, 22, 33]
[2, 4, 6]Nest literals and you have a matrix — m[0] is a row, .shape tells you
the dimensions, and use math unlocks the full toolkit (zeros, eye,
matmul, reductions along axes — chapter 10 puts it to work):
1 2 3
m = [[1, 2], [3, 4]]
log[m[0]]
log[m.shape]expected output — from the book, verified by crow test --book
[1, 2]
[2, 2]