Skip to content

Latest commit

 

History

History
99 lines (80 loc) · 4.38 KB

File metadata and controls

99 lines (80 loc) · 4.38 KB

FScript vs F# / OCaml: Major Differences

Purpose

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.

Scope of the language

  • 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.

Syntax differences

let ... in

  • F#/OCaml use in heavily 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

Indentation and layout strictness

  • FScript is layout-aware and strict in specific places:
    • match case lines must align.
    • multiline record type fields in type declarations must align.
  • F#/OCaml tooling/parsers are generally more permissive/flexible depending on construct and separators.

Generic angle-bracket syntax

  • 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 list
    • int option
    • string map

Type-system differences

Named record types vs structural records

  • 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.

Type annotations (optional, function-focused)

  • 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)
  • Pattern-level type annotations are supported in match:
    • structural: | {| Name: string |} -> ...
    • declared-type-by-shape: | { Name: string } -> ...

Recursive types

  • Recursive record declarations must be explicit: type rec Name = { ... }.
  • Mutual recursive type groups are not supported (and declarations are not available).

User-declared ADTs / discriminated unions

  • FScript supports top-level union declarations and union-case matching.
  • type rec is 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.

Pattern matching differences

  • FScript supports wildcard, literal, tuple, list-cons, option, record, and union-case patterns in match.
  • Record patterns are supported in match cases, not in let patterns.
  • Pattern features are narrower than full F#/OCaml pattern systems.

Runtime and ecosystem differences

Compilation model

  • F#/OCaml are compiled languages.
  • FScript is interpreted (parse -> infer -> evaluate).

Standard library model

  • 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.

Reflection-style type tokens

  • FScript provides typeof Name tokens for host extern workflows (for example JSON/XML decode helpers).
  • This is a focused runtime integration feature, not full .NET/OCaml runtime reflection.

Practical porting checklist

  • Replace let ... in with 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 + match where possible.
  • Check indentation alignment for match cases and multiline type fields.