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

What are the pro’s and con’s of each.
How do the communities compare.

2 Likes

The question you’re asking seems too broad to be answered.
Please show the research you have done and the specific interrogations you have.

4 Likes

For a quick answer, you can compare the two’s subreddits, this forum and fsharp’s forums for comparison.

As for personal opinion, both communities share similar properties because they’re both small. Full of enthusiasts and niche professionals. But if you’re asking on where to start, might as well try both.

Ocaml:
Setup opam, dune, lsp. Write your typical applications from your domain. Web dev is less mature than .net’s because .net has aspnet and all the c# libs. But working with linux and systems stuff feels nicer in ocaml imo.

F#:
get rider. install .net cli. Same thing.

I’ve been doing a lot of f# past couple months. While I do miss having an entire system written primarily in fp style, it’s pretty nice to have a bunch of libraries available. Example: wrote a discord bot in f# in a few hours as opposed to having to learn async+add features to disml.

4 Likes

My research tells me there are alot of similarities.
But that’s not the point. The point is what are the differences.
At this moment i’ll learning both languages , but can’t point which is best iin which situation.

I previously did some very very brief research into this issue. My goal at the time was to get a language that (1) had Hindley Milner type system (2) had a REPL (3) ran in browser (4) had LSP support in browser.

On the OCaml side, GitHub - patricoferris/try-eio: Try OCaml Effects and Eio in your browser hit all the requirements.

On the F# side, I found https://fable.io/ but never tried it due to (1) not familiar with dotnet (2) not familiar with running dotnet on Linux.

2 Likes

It may be helpful if you define you’re really looking to do. It would also help if you share what you’ve researched. Are you looking for production work or more exploratory? Just scripting against web apis, against linux apis? Perhaps sharing bits of your research can help others curate answers for you.

Here’s a fun looong discussion of the hard bits of OCaml for beginners: What are the biggest reasons newcomers give up on OCaml? - #251 by olleharstedt.

I’ll reiterate the same points everyone always point out, and also share personal one.

  1. I like knowing that I can produce a single executable. Idk why, but it just feels simpler. In practice, everyone has a CI + dockerfile for their specific OS anyways.
  2. You can basically do more “real” functional programming in OCaml because OOP is much less used. I dislike having to wrap functions from C# that throws exceptions, which a lot do. Even a simple LINQ method like .First throws an exception. It’s not hard to wrap but it just eats time.
  3. And my personal favorite feature: you’re now cool because you get to be the one of the first to ever try algebraic effects in an industry-used language and see how a language evolves from single threaded to multi-threaded.
3 Likes

dotnet in 2023 is really easy to deploy on linux and macos if you’re using docker. https://learn.microsoft.com/en-us/dotnet/core/docker/build-container?tabs=windows

but the dotnet runtime also runs fine too without docker since they’ve made it cross platform some years back.

2 Likes

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.

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

3 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

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

7 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

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