Tuples, Lists, and Dictionaries
Rex supports several lightweight data shapes.
Tuples
Tuples group fixed-position values:
(1, "hi", true)
Rex supports tuple patterns in match and let. For indexing, use numeric projection
like .0 and .1.
Indexing tuples with .
let t = (1, "hi", true) in t.1
Lists
List literals use square brackets:
[1, 2, 3]
Under the hood, lists are a prelude ADT List a with constructors Empty and Cons.
You can construct cons cells either as Cons h t (normal constructor call style) or with h::t sugar.
let xs = 1::2::3::[] in xs
match [1, 2, 3] with {
case Empty -> 0;
case Cons h t -> h;
}
List patterns (sugar)
Rex also supports list-pattern sugar:
match [1, 2, 3] with {
case [] -> 0;
case [x] -> x;
case x::xs -> x;
}
Lists At Host Boundaries
Rex exposes one ordered collection type: List a. User-written list literals,
list constructors, pattern matching, and Rust host Vec<T> values all use this
same type.
Internally, the runtime may store a list as linked Cons / Empty cells or as
a slice over contiguous heap data. Rex code does not need to choose or convert
between those representations.
let
data = [1, 2, 3]
in
match data with {
case x::xs -> x;
case [] -> -1;
}
For embedders, a Rust function returning Vec<i32> is exposed in Rex as
returning List i32, and a Rust parameter of type Vec<i32> accepts any Rex
List i32.
Dictionaries (records / dict values)
Dictionary literals use braces:
{ a = 1, b = 2 }
These are “record-like” values. Depending on context they may be treated as a record type
({ a: i32, b: i32 }) or as a dictionary-like value; either way, you can project fields when the
field is known to exist:
type R = R { a: i32, b: i32 };
let r: R = R { a = 1, b = 2 } in r.a
Forcing a dictionary type
If you want a polymorphic “dictionary” (instead of a specific record type), use type ascription
with is:
({ a = 1, b = 2 }) is Dict i32
Matching dictionaries
Dictionary patterns check for key presence and bind those keys to variables:
let d = ({ a = 1, b = 2 }) is Dict i32 in
match d with {
case {a, b} -> a + b;
case {a} -> a;
case {} -> 0;
}
{} is useful as a fallback: it requires no keys, so it matches any dict.