How does ocaml compare to F# in the family of ml languages

I agree that this kind of question is easier to answer if one specifies particular constraints that one is interested in. However, these are not just two members of the ML-family, as would be the case if we were comparing OCaml and SML. As I understand it, F# began as a revision of OCaml for .Net, so the similarities should be pretty deep.

I was thinking about this lately and was wondering whether I would be happier using F# instead of OCaml because of F#'s library ecosystem. That’s a big investment, though, so I was looking for comparisons similar to what @Alain_De_Vos1 requested. Not about anything specific, but more like “Here are some things that might be attractive or unattractive for such and such kinds of work” (whatever the author knows about). That would be informative, even if my use cases were different. It was sort of surprising to me, in a sense, that there were not a lot of blog posts or other essays discussing differences and pros and cons of OCaml and F# for different use cases, programming style, programming values, etc. I think there should be or could be more of that, but I knew that I had not seen them in the past, and there still doesn’t seem to be much of that sort of thing.

In this forum, I see comparisons to Rust, Julia, Go, and other languages much more often than the occasional cases in which F# is mentioned. Similarly, when I peek into the F# world, I rarely see any mention of OCaml. In both cases, it’s almost as if the other language doesn’t exist. Which at first glance seems kind of strange. (Sometimes I’ve wondered whether it would make sense, in theory, to have combined OCaml/F# forum. It probably doesn’t make sense, though, for reasons given below.)

It’s clear to me now that maybe there are just a lot of … cultural(?) difference between the two communities. It’s an impedance mismatch. When I examine F# books, blogs, discussions, and podcasts, there’s a lot of focus on Windows–though that’s not required–and C# comparisons, and the whole .Net world. It is a different world. There’s a lot of discussion of stuff that’s just irrelevant to anyone working in OCaml. Analogously, OCaml folks tend to be focused on unixes–though that’s not required–and you don’t have to learn about .Net-isms because the OCaml library universe is self-contained (except when calling out to other, e.g. C binary libraries)–so why would F# people be interested in all of that? Sure, at their roots the languages are very similar, but discussions of programming in either language involve a lot more than the core similarities.

But … I still think it could be good for the world, in principle, if there were more discussion of the languages in one breath, with discussions of tradeoffs and common advantages of the two languages. In theory. I’m not sure that that could practical for a lot of people to engage in, and perhaps there are few people who would want to do that if they are well-positioned to do so.

Even if you could have a common overlapping F#/OCaml forum for discussion of, say, algorithms and techniques that would be common to both, discussions would often quickly veer off into territories that would be foreign to folks on the other side of the divide.

2 Likes

Currently I installed Windows-dotnet & mono on Gentoo-linux.
Dotnet runs really fine on Linux i.e. it’s really cross-platform.
As editor i use vscode with Ionide plugin.
When i code in ocaml i use as editor neovim with “merlin” plugin.
Both show “function-hints” and “errors” as you type, so they behave more or less the same.

1 Like

One specific point about some tradeoffs that I see. I like the idea that F# has .Net libraries available. But I don’t want to learn .Net.

I also use Clojure a lot, and once you get beyond a certain point with Clojure, it’s very helpful to know a little Java. But I already knew some Java when I started using Clojure, so that wasn’t a problem. (The fact that Clojure has access to the world of Java libraries was one of the reasons that it was attractive to me in the first place.)

OCaml doesn’t require that I learn about an entire world of programming in a language that is not OCaml. I think using F# would require that I spend time learning about C# and .Net in order to make full use of F#. I might like the benefits of that knowledge, but I don’t want to have to spend time acquiring it. :slight_smile: My interest in functional programming doesn’t make me want to have to study a currently unfamiliar OO world. I have limited time.

2 Likes

OCaml is a significantly bigger language in terms of programming languages core features / programming language research derived features, and also compilation targets. (Functors, recursive modules, first class modules, structural object-orientation, polymorphic variants, polymorphic recursion, labeled function parameters, algebraic effects, integrated preprocessor PPX, compiling to bytecode / AMD64 / ARM64 / powerpc (not sure?) / riscv / JavaScript.) But I might have forgotten about some F# features.

3 Likes

F# started as basically a port of OCaml for dotnet, with some stuff removed or changed to fit the CLR better. But it grew its own features that make it interesting as a language of its own, some of which include:

  • support for static operator overloading (limited but done reasonably well; relies on inline functions and statically resolved type parameters which are pragmatic ways to get some specialization)
  • active patterns (first-class pattern synonyms if you want)
  • some support for value types
  • computation expressions, a general form of monadic/applicative/comprehension style
  • units of measure
  • type providers
7 Likes

You might find Paul Biggar’s discussion of moving from OCaml to F# useful. Paul Biggar on Darklang

2 Likes

I’ll give some pros and cons of F#, you can deduce that OCaml has almost the exact inverse of these pros and cons.

+ Access to .NET ecosystem
- Have to learn C# pretty deeply to understand how to use most .NET libraries/frameworks from F#
+ Language created and supported by Microsoft
- Toolchain and support lags behind C# on the platforms where they are both supported
+ Type providers are a type-safe way to easily access JSON and many other kinds of data
- Need to manually arrange source files in compilation order
- Compile speeds slower than OCaml
- Lacking support for functors, abstraction can be done with interfaces only
- Native compilation is not very advanced and output executables will be bloated with .NET runtime

6 Likes

Random things not mentioned above:

  • F# has units of measure (@gasche mentioned it, but adding a link)
  • F# does not have named arguments (in normal functions), which I am reminded of constantly when I use it
  • The type inferencing in F# isn’t quite as good, but can’t put my finger on why. I have to annotate things more.
  • Fable, an F#->Javascript compiler, is nice.
  • The F# code formatting options are not as good as ocamlformat, IMO, but I expect it’s because whitespace is semi-significant in F#
  • No sexp, bin-prot, etc though there is something vaguely like ppx that means it should be possible
  • The first-class(ish) async is nice, no lwt/async/eio schism like in OCaml
  • Calling C code from F# looks like it might be easier, haven’t poked at it too deeply yet
  • I haven’t tried doing GUI apps in it but I suspect it’s a slam-dunk whereas in OCaml it’s… lets say absolutely not a slam dunk

That all said, F# really isn’t as good as OCaml IMO, but the .NET integration + ecosystem is what makes it more valuable in general if that stuff is even a little bit relevant. The inherent C# weirdness of .NET is awkward but you can generally power through learning it with ChatGPT.

6 Likes

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
5 Likes

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.

4 Likes

Still no good comparison between the two is lacking.
[Whereas comparison to rust or scala is available ]

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.

1 Like

OCaml has better taste. :wink:

5 Likes

…and stickers OCaml Stickers via 🐌 … going on!

3 Likes

@mro Received mine! Thanks alot. It came as a surprise haha

1 Like

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.

1 Like

ocaml has a nice binding to the tk library to make a gui.
F# has not.

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.

3 Likes

I might oversimplify but you convert a null-pointer to an option type and back ?

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™

5 Likes