Skip to content

Collections

Collections are values. “Changing” one gives you a new value and leaves the old one intact. When the compiler can prove the old version is never read again, it updates in place, so you get value semantics at the cost of a mutable data structure.

Int main() {
List(Int) xs = [3, 1, 2];
List(Int) more = xs.concat([10, 20]);
println(f"{xs} {more} {more.len()}");
println(f"{more[1..3]} {sort(xs)} {xs.reverse()}");
println(f"{xs.contains(2)} {xs.sum()}");
return 0;
}
Output
[3, 1, 2] [3, 1, 2, 10, 20] 5
[1, 2] [1, 2, 3] [2, 1, 3]
true 6

Indexing is bounds-checked; an out-of-range index aborts with the index and the length. An empty list needs its type from the binding: List(Int) none = [];.

Int main() {
Map(Str, Int) ages = {"ada": 36, "alan": 41};
Map(Str, Int) more = ages.insert("grace", 85);
println(f"{ages.len()} {more.len()} {more.contains("grace")}");
Int a = ages.get("ada") else { 0 };
Int z = ages.get("zed") else { -1 };
println(f"{a} {z}");
List(Str) names = sort(more.keys());
println(f"{names}");
return 0;
}
Output
2 3 true
36 -1
["ada", "alan", "grace"]

m.get(k) (or m[k]) returns an Option; else supplies a default. insert and remove return the new map. Map iteration order is by key hash, so sort keys when order matters.

Int main() {
Set(Int) a = {1, 2, 3};
Set(Int) b = {3, 4};
println(f"{a.union(b).len()} {a.intersection(b).len()} {a.difference(b).len()}");
println(f"{a.contains(2)} {a.insert(9).len()}");
return 0;
}
Output
4 1 2
true 4

Each concat builds a new list. To produce a big list piece by piece, use a linear builder: ListBuf(T) (and StrBuf for strings) appends in place because the compiler guarantees each builder value is used exactly once:

ListBuf(Int) squares(Int i, Int n, ListBuf(Int) acc) {
if (i >= n) { return acc; }
return squares(i + 1, n, acc.push(i * i));
}
Int main() {
List(Int) sq = squares(0, 6, ListBuf()).finish();
println(f"{sq}");
return 0;
}
Output
[0, 1, 4, 9, 16, 25]

See Linear builders for the rules.