OCaml's approach to semicolons is nice—they are clearly nothing more than sequence markers between side-effecting expressions.
a ; b (* a THEN b *)
a b (* a APPLIED TO b *)
You also can basically just desugar them to let bindings a ; b
==
let _ = a in b
a ; b ; c ; d e
==
let _ = a in
let _ = b in
let _ = c in
d e
Due to static typing it's vanishingly unlikely that a forgotten semicolon will properly check. let this = x ; y (* if x : 'a and y : 'b then this : 'b *)
let this = x y (* if x : 'a -> 'b and y : 'a then this : 'b *)
So forgetting a semicolon only check if `x` is an unapplied function of type `'a -> 'a` which the value you intended to completely ignore.