Morel Cookbook

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