This document describes core language choices and conventions used in FScript.
- Local and nested bindings use layout blocks.
letexpressions are indentation-based and compose naturally in blocks.
Example:
let x =
let y = 1
y + 1- Container types use postfix syntax:
'a list'a option'a map
- Map values use native literals:
{ ["a"] = 1; ["b"] = 2 }
- Map update/merge is available directly in literals:
{ ["a"] = 1; ..tail }
- Function types use arrow syntax:
int -> stringint -> int -> int
- Top-level record declarations:
type Name = { ... }type rec Name = { ... }
- Top-level discriminated union declarations:
type Shape = | Point | Circle of inttype rec Tree = | Empty | Node of (int * Tree list)
- Recursive records are declared explicitly with
type rec. - Recursive unions are declared explicitly with
type rec.
- Parameter annotations use parenthesized form:
let f (x: int) = ...fun (x: int) -> ...
- Let-bound function return annotations use
: Typebefore=:let f x : int = ...
- Parameter annotations support two inline record forms:
- structural:
let f (x: {| Name: string; Zip: int |}) = ... - declared-type-by-shape:
let f (x: { Name: string; Zip: int }) = ...
- structural:
matchsupports wildcard, literal, tuple, list-cons, option, record, and union-case patterns.- Record patterns are used in
matchcase heads.
- Language core stays minimal.
- Host capabilities are exposed through explicit extern functions.
- Typed decoding workflows use
typeof Nametokens with host externs. - Capability maps can use
nameof identifierfor stable script-side function keys. - Capability maps use string keys in map literals (
[expr]whereexpr : string).
matchcase columns align.- Multiline record type fields align.
- Multiline union case lines align in their block.
- These layout rules keep parser behavior explicit and predictable.