F# does runtime monomorphisation whereas OCaml uses an uniform representation through pointer-tagging on a single machine word. Thus in F# you can easily observe the JIT causing pause time in the execution. E.g. if you implement Okasaki’s random access lists:
type ral<'a> =
| Nil
| Zero of ral<'a * 'a>
| One of 'a * ral<'a * 'a>
let empty = Nil
let rec length<'a> (l : ral<'a>) : int =
match l with
| Nil -> 0
| Zero s -> 2 * length s
| One (_v, s) -> 1 + 2 * length s
let rec cons<'a> (x : 'a) (l : ral<'a>) : ral<'a> =
match l with
| Nil -> One (x, Nil)
| Zero s -> One (x, s)
| One (y, s) -> Zero (cons (x, y) s)
let rec loop l =
let len = length l
if len < 3000000 then
let l = cons 42 l
printfn "len = %d" (length l)
loop l
loop empty
loop empty
If you do fsharpc ral.fsx && chmod +x ral.fsx && ./ral.exe, on the first call to loop empty you’ll see the JIT in action, causing bigger pause time each time the length of the loop is doubling (short version). On the second call there’s no such pause as the function has already been specialised for all cases it’ll encounter.
Here’s the OCaml equivalent:
type 'a t =
| Nil
| Zero of ('a * 'a) t
| One of 'a * ('a * 'a) t
let empty = Nil
let rec length : 'a. 'a t -> int = function
| Nil -> 0
| Zero s -> 2 * length s
| One (_v, s) -> 1 + 2 * length s
let rec cons : 'a. 'a -> 'a t -> 'a t = fun x -> function
| Nil -> One (x, Nil)
| Zero s -> One (x, s)
| One (y, s) -> Zero (cons (x, y) s)
let rec loop l =
let len = length l in
if len < 3000000 then begin
let l = cons 42 l in
print_endline "len = %d" (length l);
loop l
end
let () =
loop empty;
loop empty
You might find Don Syme’s talk on The Early History of F# and the paper interesting — the paper mentions OCaml quite a few times. And, on the same note, Xavier Leroy’s talk on 25 years of OCaml might also interest you.
What are you looking for? Can you share the rust vs scala comparison you’re referring to? There’s many good comments here explaining a lot of good differences.
There are alot of communalities. If you know one you know the other.
One small difference on syntax are:
-Ocaml uses keyword “in” and “;” operator , whereas F# uses indentation and spaces.
-F# uses <> around type types.
F# history is perfectly captured in The Early History of F# and how it relates to ML family of languages. There are missing / added language features on both sides, I missed the module system the most in F#.
On the practical side, I found developing F# to be quite foreign as a life long Unix person. The libraries from .NET really expect you to know C# and the build/package tooling had a distinct Windows feel to it. We used VS Code or Visual Studio for development, it worked ok, the .NET devs I worked with really liked it and the IDE experience. My preference is for Emacs as an editor, which I did manage to get working but it wasn’t that well integrated (it could have improved via lsp-mode in the last few years). The practicalities of using .NET libraries meant you had a library for almost anything, if you were ok wrapping it in F#, often the libraries had C# documentation and APIs, which felt very non-FP. Null pointers and mutablity from C# caused us problems at various times. F# is a decent choice if you already know and use Windows/.NET.
completely subjective and quite frankly useless opinion from my time playing with F#:
F# tooling has MS smell to it, OCaml tooling feels more UNIX-y. Also less ceremony and whatnot to produce e.g. an executable from a single file.
I like that OCaml is insensitive to indentation.
F# feels more pragmatic, but less satisfying. OCaml gives me more power while feeling leaner to work with
I envy some strides F# made, but I don’t like the idea of replicating them. I like that OCaml adds features in principled ways.
OCaml feels more coherent, things interact with each other more nicely.
F# has even worse value restriction rules than SML, let alone OCaml.
Nothing Ever Beats OCaml’s Compilation Speed™
Very basically yes, it gets more complicated with larger structures that might contain nulls. Think of it as a validation boundary within the overall system, things from C# get checked and transformed to be safe for F# to use. I think of it similar to validating json data into domain types.
After spending some time with F# , i find the (F#/C#) libraries&API’s much better documented then the corresponding Ocaml libraries. Eg explicit examples are given.
I think I agree with most of this, but I kind of miss the need to manually arrange source files in compilation order just because it serves as documentation for newcomers starting to learn a codebase (with the first file not being dependent on any after it). Maybe there is something similar that can be automatically generated in OCaml and manual documentation is an option too.
The only arrangement is like this example. Some IDEs like Visual Studio and plugins like Ionide for VS Code give an easier way to arrange it than typing XML.