This document is a quick comparison guide. It highlights intentional differences between FScript and full F#/OCaml so users can port code with fewer surprises.
- FScript is a small interpreted subset, not a full compiler language.
- FScript supports a focused core:
let,let rec(functions),if/elif/else,for,match, lists, tuples, options, records, discriminated unions, pipelines, and extern calls. - Many F#/OCaml features are intentionally absent today (classes, interfaces, computation expressions, etc.). Script composition uses
import, and imported files are exposed through filename-derived modules.
- F#/OCaml use
inheavily for local bindings. - FScript does not support
in; it uses layout/indentation blocks instead.
Example:
// F#/OCaml style
let x =
let y = 1 in
y + 1// FScript style
let x =
let y = 1
y + 1- FScript is layout-aware and strict in specific places:
matchcase lines must align.- multiline record type fields in
typedeclarations must align.
- F#/OCaml tooling/parsers are generally more permissive/flexible depending on construct and separators.
- F#/OCaml often use forms like
list<string>(or equivalent library forms). - FScript does not support angle-bracket generic syntax.
- Use postfix type syntax:
string listint optionstring map
- FScript uses structural records and also supports top-level named record declarations.
- In current behavior, declared record names can unify with matching record shapes (structural equivalence), including recursive records.
- FScript supports optional parameter annotations using F#-style syntax:
let f (x: int) = ...fun (x: int) -> ...
- FScript supports optional let-bound function return annotations:
let f x : int = ...
- FScript also supports two inline record annotation forms:
- structural (explicit):
let f (x: {| Name: string; Zip: int |}) = ... - declared-type-by-shape:
let f (x: { Name: string; Zip: int }) = ...(must resolve to a declared record type)
- structural (explicit):
- Pattern-level type annotations are supported in
match:- structural:
| {| Name: string |} -> ... - declared-type-by-shape:
| { Name: string } -> ...
- structural:
- Recursive record declarations must be explicit:
type rec Name = { ... }. - Mutual recursive type groups are not supported (
anddeclarations are not available).
- FScript supports top-level union declarations and union-case matching.
type recis required for recursive union declarations, consistent with recursive records.- Constructor payloads are a single type; multiple payload values can be modeled with tuple payloads.
- Mutual recursive type groups (
type ... and ...) are not supported.
- FScript supports wildcard, literal, tuple, list-cons, option, record, and union-case patterns in
match. - Record patterns are supported in
matchcases, not inletpatterns. - Pattern features are narrower than full F#/OCaml pattern systems.
- F#/OCaml are compiled languages.
- FScript is interpreted (parse -> infer -> evaluate).
- F#/OCaml ship large standard libraries.
- FScript has a smaller built-in surface and relies on host-provided externs for host/system capabilities (for example
Fs.*,Json.*,Xml.*,Regex.*), while collection helpers are provided by the embedded prelude.
- FScript provides
typeof Nametokens for host extern workflows (for example JSON/XML decode helpers). - This is a focused runtime integration feature, not full .NET/OCaml runtime reflection.
- Replace
let ... inwith indented block bindings. - Replace generic angle syntax with postfix syntax (
'a list,'a option,'a map). - Keep annotations on function parameters and, when helpful, explicit function returns.
- Convert unsupported modules/features into records + functions +
matchwhere possible. - Check indentation alignment for
matchcases and multiline type fields.