F# for Elm developers

The F# syntax is very close to the Elm one. Some people actually moved from Elm to F# after Elm v0.19. So I gave F# a try and was surprised by how close you can get to the Elm experience.

I created a little example GitHub repo with typical Elm features:

The goal of this example is to show how to get typical Elm features (see below) in F#. It uses Fable to transpile F# to JavaScript and Elmish to get The Elm Architecture (TEA), also known as the Model View Update (MVU) pattern.

Elmish normally uses React under the hood, but in this example React was seamlessly replaced by Preact to get performances similar to Elm, both in term of speed and bundle size.

Featuring

  • Startup flags
  • Getting a random number (easy!)
  • Routing
  • Subscription via a JavaScript custom event
  • Foreign Function Interface (FFI) using synchronous and asynchronous functions imported from JavaScript
  • JSON decoding
  • Keyed list
  • Unit tests
  • Hot Module Replacement (HMR)
  • Debugger (via Redux DevTools)

Note that F# is backed by Microsoft since 2005 and is updated regularly, unlike ahem, well some other languages :smirk:

12 Likes

I always tell people to look up F# for Fun and Profit as a solid knowledge base of statically-typed functional programming. My go-to recommendation.

And yes I’m looking for opportunity to use F# in an actual projects but got too much comfortable in Elm lol

2 Likes

Essential F# is also very good. For TEA/MVU based apps there is The Elmish Book.

Disclaimer: I didn’t read them :wink:

1 Like

I have used F# professionally and I liked the book “for fun and profit” plus that F# is the nicest .Net language,

There are however things I didn’t appreciate:

  • interop with .Net means you can get null pointers in your code despite the language has no null concept.
  • single pass compiler (!) You need to declare things before using them. Haven’t seen a single pass compiler since the 80’s.
  • it has not this nice sense of simple and yet complete that Elm has. You sometimes need to reach for something written in C# and the impedance is significant.
  • it has this aurora of "designed by Microsoft " over it, hard to describe, the best I can is “paper cuts”. Overall nice idea but annoying things here and there.

Your experience may be different, of course. This is just me.

3 Likes

EDIT: The debugger (via Redux DevTools) is now working and it is even better than the Elm one.

I think you can fix this with the module rec syntax.

I find having the order of declarations enforced at compile time quite refreshing actually. I find that it makes reading code more predictable/enjoyable.

F# is an interesting language, but I find myself more interested by its ancestor OCaml :slight_smile:

I’ve been playing with an interesting OCaml library, “fmlib_browser”, that implements TEA. You can find an example here: tea-playground/ocaml/fmlib/combine-http-requests-parallel/main.ml at e9b893fbdcaf3d08ea05f36f4476c9bbbba59b91 · benjamin-thomas/tea-playground · GitHub

It’s not Elm, but feels very close (closer than Elmish IMO).

Regarding Elmish, I find its heavy use of exceptions in Cmd Msg a little bit off-putting.

Have you found a good justification for doing so vs returning a Result in an Async wrapper type?

3 Likes

Is Cmd.ofAsync an example of what you mean?

Yes that’s it.

It seems like the framework encourages you to throw exceptions to signal errors. This design decision seems pretty baked-in.

There is a section about this choice in FSFFAP. F# handles exceptions because it allows FFI. Elm evacuates the problem by using ports and custom elements. I would need to implement a non-trivial app in F# to be more assertive, but I think you can do the same in F# if you handle JS exceptions on the JS side before sending proper “Result” records to F#. I agree we are spoiled by Elm design choices that enforces cleanliness for us!

1 Like

You’re right that it’s baked-in, and this does steer you into a pattern. I don’t think it would be hard to create say “Cmd.Result.ofAsync” , “Cmd.Either.ofAsync” etc. I hadn’t thought about this before, and may add it into my own project.

By the way I just listened to @rtfeldman’s podcast episode with the author of F# for fun and profit, and at minute 18 they start to talk about Result versus exceptions. They confirm that in a “pure Result environment” there is no need for exceptions but as long as you run code that can raise exceptions you have no choice but to handle exceptions. Obvioulsy.

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.