Standard Library · expr
class Expr<F>
A lambda together with a walkable description of its body.
since 0.1.0-alpha.1linuxwindowswasm
Overview
Where a parameter or variable has type expr::Expr<F>, a lambda literal produces both parts: fn is the ordinary closure, and tree, binds and siteId describe the same body as data. The tree mirrors the checked body of the lambda, so a consumer such as a query builder can translate it instead of running it. The body must be a single expression, and only a fixed subset of expressions can be reified; anything else is a compile error that names the construct.
The example evaluates a reified lambda two ways: by calling fn, and by walking tree with the values in binds.
Examples
Evaluating a reified lambda
class User { int age; new User(int a) { age = a; } }
int asInt(string | int | float | bool | None v) {
match (v) {
int => { return v; }
else => { return 0; }
}
}
// A small walker for the nodes this lambda produces: it evaluates
// Field, Lit, Bind and comparison Bin nodes over a User.
bool evalNode(expr::Node n, User u, Array<string | int | float | bool | None> binds) {
int value = evalInt(n, u, binds);
return value != 0;
}
int evalInt(expr::Node n, User u, Array<string | int | float | bool | None> binds) {
match (n) {
expr::Field => { return u.age; }
expr::Lit => { return asInt(n.v); }
expr::Bind => { return asInt(binds[n.slot]); }
expr::Bin => {
expr::Bin b = n;
int x = evalInt(b.l, u, binds);
int y = evalInt(b.r, u, binds);
if (b.op == ">=") { if (x >= y) return 1; return 0; }
throw RuntimeException("unhandled operator " + b.op);
}
else => { throw RuntimeException("unhandled node"); }
}
}
int minAge = 18;
expr::Expr<(User) => bool> adult = (u) => u.age >= minAge;
console.writeln("captured values: ${adult.binds.length()}");
console.writeln("closure: ${adult.fn(User(20))} ${adult.fn(User(15))}");
console.writeln("tree: ${evalNode(adult.tree, User(20), adult.binds)} ${evalNode(adult.tree, User(15), adult.binds)}");
captured values: 1
closure: true false
tree: true false
Constructors
new
new(F f, expr::Node t, Array<string | int | float | bool | None> b, int s)Build an Expr from its four parts.
The compiler calls this for you when a lambda literal reifies; calling it yourself is useful for hand-built trees.
Parameters
- f
- The closure.
- t
- The root of the node tree.
- b
- The captured values.
- s
- The site identifier.
Examples
Array<string | int | float | bool | None> binds = [];
expr::Expr<(int) => int> e = expr::Expr((x) => x + 1, expr::Bin("+", expr::Field(["x"]), expr::Lit(1)), binds, 7);
console.writeln(e.fn(4));
console.writeln(e.siteId);
5
7
Fields
binds
Array<string | int | float | bool | None> bindsThe captured values the tree refers to by Bind slot, each read once when the Expr was built, in order of first use.
fn
F fnThe lambda as an ordinary closure; call it like any function.
siteId
int siteIdA number that identifies the lambda in the source program, unique within one compilation.
tree
expr::Node treeThe root of the node tree that mirrors the lambda body.
See also
- Node — The base class of every node in the reification tree.