Problem
I want to build a tuple, a record, and a list, and I want to pull a field or an element back out. In one place.
Example
val name = "Earl Grey";
val price = 18.50;
val pair = ("Earl Grey", 18.50);
val (product, cost) = pair;
val row = { id = 1, product = "Earl Grey", quantity = 12 };
row.product;
#quantity row;
val { id = i, product = p, quantity = q } = row;
val prices = [18.50, 24.00, 16.00, 22.00];
hd prices;
tl prices;
length prices;
val first :: rest = prices;
What's happening
Three shapes, one val keyword. Scalars (name, price) bind a
literal. Tuples (pair) are positional — handy when the pair is
"thing and its price" and naming would be overkill. Records (row) are
named fields, which is what you want for anything that will travel
through a query: the query operators know the field names, so yield { row.product } means the same thing after any rearrangement.
Three ways to pull a field out. Postfix dot (row.product) is the
everyday form and reads well in pipelines. #quantity row is the
older SML spelling and still works — useful when you want to treat
"field access" itself as a function. Full destructuring in a val
pattern (val { id = i, ... } = row) binds several names at once and
shows up all over pattern-matching code.
Lists are the [a, b, c] literal plus the cons cell a :: rest.
Queries return lists, so hd, tl, and the first :: rest pattern
are the bread and butter for anything you do outside a from
expression.
One rough edge in 0.8: the partial record form val { product, ... } = row that SML normally allows crashes at runtime with a class-cast
error. Name every field you want until 0.9 lands, or skip
destructuring and use row.product directly.
Variations
Tuples can be any arity. A three-tuple binds three names in one go:
val (a, b, c) = (1, "two", 3.0);
Lists hold one type and only one — Morel infers it from the elements. Mixing types is a compile error:
val mixed = [1, "two"];
See also
- Recipe 01 — First query — where records and lists first show up in a
fromexpression. - Recipe 08 — Select and rename columns — record construction in the yield step of a query.