Skip to content

Latest commit

 

History

History
101 lines (82 loc) · 4.5 KB

fsharp-ocaml-differences.md

File metadata and controls

101 lines (82 loc) · 4.5 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 accessed through explicit aliases (import "shared.fss" as Shared).

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 (string keys)
    • string map[int] (int keys)
    • string map[Priority] (payload-free union keys)

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