This document specifies the value and type system used by the interpreter.
unitint(int64at runtime)floatboolstring
- List:
'a list - Tuple:
(t1 * t2 * ...) - Option:
'a option - Map (string-keyed alias):
'a map - Record: structural record types
- Discriminated union: named union types with cases
- Native map literal syntax:
- empty:
{} - populated:
{ ["a"] = 1; ["b"] = 2 } - spread update:
{ ["a"] = 1; ..tail } - multiline entries are supported in an indented block.
- empty:
- Keys are bracketed expressions and must have type
string(for example{ [keyExpr] = value }). - Record literals and map literals share
{ ... }braces:- map entries use
[expr] = value - record entries use
Field = value {}denotes an empty map.
- map entries use
- Values are inferred and unified to a single value type.
- See
./map-matching-reference.mdfor focused map-pattern examples.
- Lists support optional zero-based index access with integer keys (for example
values[0]). - Maps support optional key lookup with string keys (for example
scores["math"]). - Negative or out-of-range list indices return
None.
- Type form:
'a list - Indexer signature:
'a list -> int -> 'a option - Notes:
values[index]is zero-based- negative or out-of-range indices return
None
- Type form:
'a map - Indexer signature:
'a map -> string -> 'a option - Notes:
values[key]performs optional lookup- keys must be
string
- Field access signature:
{ Field: 'a; ... } -> 'a - Notes:
- records use named field access (
record.Field)
- records use named field access (
- Access model:
- tuples are consumed by destructuring and pattern matching
- tuples do not expose a native indexer
- Constructors:
Some : 'a -> 'a optionNone : 'a option
- Functions use curried arrow types:
t1 -> t2t1 -> t2 -> t3is right-associative
- Function type syntax is available in parameter annotations.
- Parameter annotations support two inline record type forms:
- structural:
let f (x: {| A: int; B: string |}) = ... - declared-type-by-shape:
let f (x: { A: int; B: string }) = ...
- structural:
{ ... }resolves only if exactly one declared record type matches that shape.- Inline record annotation fields are semicolon-separated in single-line form.
- Top-level record declarations:
type Name = { ... }type rec Name = { ... }
- Recursive record references use
type rec. - Named record types and matching record shapes unify structurally.
- Top-level union declarations are supported:
type Shape = | Point | Circle of inttype rec Node = | Empty | Branch of (int * Node list)
- Union case names start with an uppercase identifier.
- A case payload is optional:
- no payload:
| Point - payload:
| Circle of int
- no payload:
- Payloads are single-type payloads; tuple payloads are used for multi-value payloads.
- Union cases are constructors in expression position:
let x = Circle 3let p = Point
matchsupports union-case patterns:| Circle r -> ...| Point -> ...
optionvalues (Some/None) are also represented as union-style constructors and patterns.
- Hindley–Milner style inference.
- Let-polymorphism.
- Structural typing for record values.
- Field access is typed when the target expression is inferred as a record.
VUnit,VInt,VFloat,VBool,VStringVList,VTupleVRecordVMapVOptionVUnionCase,VUnionCtorVClosureVExternalVTypeToken
typeof Nameyields a type token.nameof identifieryields the bound identifier name asstring.- Type tokens are consumed by host externs (for example JSON/XML decoding).