I have been writing full-stack web apps in Haskell using functional reactive programming (Reflex-FRP) for 3 years now. Curiosity stuck me as to find out what the FP languages other than Haskell had to offer in this area.
My critieria were:
- Must be a functional programming language
- Must run natively on backend without nodeJS (rules out the likes of PureScript)
Haskell’s GHCJS (esp. when used with Obelisk) satisfies all of this, but there is one pain-point: the future of GHCJS (which has not been updated in a year) and Reflex seems to be in the hands of one small company, Obsidian Systems.
That lead me to F#, a hybrid FP language (“hybrid” because it supports OOP, which is essential to integrate with the rest of the .NET ecosystem). I’ve documented my learnings here.
What I found impressive:
- Full access to the entire .NET ecosystem of libraries and frameworks (which is larger than that of Haskell).
.NET 5.0 ecosystem is a pleasure to work with (and it works well on Linux with VSCode); and you can create cross-platform apps more straightforwardly than in Haskell, including on mobile devices.
- If I were to start developing Neuron today, I would certainly consider F# (but see below).
Microsoft has a great full-stack web development story; and they support WebAssembly (
Blazor), including a framework for real-time communication (
- In F#, Bolero today is the go-to framework to make use of the above technology.
I find it reassuring that I can rely on Microsoft to advance the full-stack web development more than one small consultancy (Obsidian Systems) with less than transparent open source development in the Haskell land.
- That said, I have some hopes that Tweag’s Asterius catches up, and the community is encouraged to proliferate a whole new ecosystem of full-stack development tools in Haskell not necessarily tied to Reflex.
Some things are better in the Haskell ecosystem, though.
Fast development reload workflow works super well in Haskell, thanks to ghcid. In .NET, you have
dotnet watch- but that recompiles the whole project on every change leading to annoying delay 1 ; it made me switch back to using Haskell for DSL-based static sites, while live-reload is essential to get quick feedback on things like CSS changes.
- Having to work with OOP-based .NET libraries (written in C#) can be an annoyance from a pure-FP perspective, though that can be dealt with by wrapping these libraries in a functional layer, and then using that in the F# program.
- Overriding dependencies to use a fork in straightforward manner is virtually impossible. You have to create a local Nuget repo containing the binary of your overriden dependency. Whereas in Haskell world, one can easily use Nix to use a Git repo (Neuron does this) as a package dependency. 2
F# will continue to remain in my toolbox. If the aforementioned downsides are addressed in some way, I might just pick it for some of the next projects over Haskell, which is still my go-to language today.