Problem
I want to write my first Morel query against a small dataset and see output in under a minute.
Example
val orders = [
{ id = 1, product = "Earl Grey", quantity = 12, region = "north" },
{ id = 2, product = "Espresso", quantity = 30, region = "south" },
{ id = 3, product = "Darjeeling", quantity = 8, region = "north" },
{ id = 4, product = "Espresso", quantity = 50, region = "west" },
{ id = 5, product = "Earl Grey", quantity = 6, region = "east" }
];
from ord in orders
where ord.quantity > 10
yield { ord.product, ord.quantity };
Output:
val it =
[{product="Earl Grey",quantity=12},{product="Espresso",quantity=30},
{product="Espresso",quantity=50}] : {product:string, quantity:int} list
What's happening
val orders = [ … ] binds a list of records to the name orders. You
didn't write a type, but Morel inferred one — every orders element has
id, product, quantity, and region, and the compiler knows their
types. The query from ord in orders where ord.quantity > 10 yield { ord.product, ord.quantity } reads like SQL but is a first-class
expression in a real programming language, which is the thing this
cookbook is about.
Three other things worth noticing. The query returns a list of records, so
you can bind the result to a name and query it again — queries compose.
Field access is postfix (ord.product) rather than prefix (#product ord), because postfix reads better in pipelines. And the output records
have a different type from the input: you dropped id and region, and
the compiler knows — see the inferred type after val it.
One gotcha: avoid o as a loop variable. It's Standard ML's
function-composition operator, so from o in orders parses as an
operator expression and won't compile.
Variations
Filter on a different predicate and yield a single field:
from ord in orders
where ord.region = "north"
yield ord.product;
val it = ["Earl Grey","Darjeeling"] : string list
Yield a computed value. bulk is a new field, typed as bool, that
didn't exist on the input:
from ord in orders
yield { ord.product, bulk = ord.quantity >= 20 };
val it =
[{bulk=false,product="Earl Grey"},{bulk=true,product="Espresso"},
{bulk=false,product="Darjeeling"},{bulk=true,product="Espresso"},
{bulk=false,product="Earl Grey"}] : {bulk:bool, product:string} list
Note how Morel sorts record fields alphabetically: bulk comes before
product in both the values and the printed type.
See also
- Recipe 02 — Values, records, and lists — the vocabulary this recipe used.
- Recipe 07 — Filter rows — multi-predicate filtering,
andalso/orelse, negation.