Language reference

This page is a short overview aligned with the Lemma language guide and language reference upstream. For the full specification, use those documents and the examples in the Lemma repository.

Structure

A Lemma file contains one or more specs (namespaces for data and rules). A spec holds data declarations (values, type definitions, references, and from imports) and rule declarations. Other specs are pulled in with uses. The engine resolves dependencies between names; write declarations in a clear order for readers, not because Lemma requires a fixed one.

spec pricing 2026-01-01

data quantity : number
data is_vip   : false

rule discount:
  0%
  unless quantity >= 10 then 10%
  unless quantity >= 50 then 20%
  unless is_vip then 25%

rule price:
  quantity * 20 - discount

uses forms include uses spec_name (alias defaults to the last path segment), uses alias: spec_name, temporal pins such as uses pricing 2025-01-01 or bare year uses pricing 2025, comma-separated bare imports uses a, b, c, and registry imports uses @org/path. Import a single field’s type with data name from other_spec (same temporal pin rules as uses).

Primitive types

  • boolean: true/false (see literals below)
  • number: dimensionless numeric values
  • scale: numeric values with user-defined units
  • text: string values
  • date: ISO 8601 dates (and datetimes where applicable)
  • time: time values
  • duration: periods such as hours, days, weeks
  • ratio : proportions; percent and permille are built-in ratio units (e.g. 21%, 15 percent, 5%%)

Named types are introduced with data: either data money: scale plus -> constraints, or data price: money -> minimum 0 extending another data type.

Boolean literals

These are interchangeable: true/yes/accept and false/no/reject.

Type constraints (->)

Common type commands (see upstream reference for the full matrix per type):

  • scale / number: unit (scale only), decimals, minimum, maximum, precision, default, help
  • ratio: unit (custom ratio units), minimum, maximum, default, help
  • text: option "…" (one allowed value per line), options "a" "b" …, length, default, help
  • date / time / duration: minimum, maximum, default, help
  • boolean: default, help

Rules and conditions

  • unless condition then value : conditional branches on a rule; when several match, the last matching unless wins (same idea as stacked exceptions in prose).
  • and, not: logical operators in conditions
  • is, is not: equality and inequality (e.g. with text)
  • in : unit conversion, not set membership: e.g. price in usd, workweek in days, 0.25 in percent
  • then veto "…" : the rule produces no value when that branch applies (domain validation). accept/reject are boolean literals, not special veto keywords. A dependent rule that needs a vetoed value is vetoed too, unless an unless branch supplies a value without evaluating the vetoed dependency.

Operators

  • Comparison: <, >, <=, >=, is, is not
  • Arithmetic: +, -, *, /, %, ^
  • Math (prefix; parentheses optional): sqrt, sin, cos, tan, log, exp, abs, floor, ceil, round

Temporal versioning

Rules and data can vary over time using multiple spec declarations for the same logical spec with different effective dates (for example spec pricing and spec pricing 2026-01-01), temporal pins on uses/from, and evaluation at an effective instant (e.g. CLI --effective). See Temporal versioning in this documentation.

For details, veto semantics, registry @ dependencies, and the full operator and type-command lists, see the Lemma repository and open an issue there if something is unclear.