Approaching functional programming through compile-to-JS languages
Published on Aug 30, 2021
4 mins read
Posted under typescript, mustache, purescript, rescript, haskell
I particularly find it easy to reason about code when it's broken into small chunks of pure functions that do one thing. It makes debugging easy when you can look at a chain of functions and go down the list, identify when the problem is not in one particular function and stop worrying about it. In my mind, being able to replace that function call with the return value makes it easier to narrow down a problem.
Pure functions also make it easy to test and ensure your logic is tight. Of course, this, by no means, is "pure" functional programming but that's the part I liked about this paradigm and practice everyday.
Of late, I have been reading up a lot on Elm, Purescript and Rescript. I'm toying around with some of these languages that compile to JS but enforce a pure functional pattern while authoring. Things that have been mental blocks for me in this journey has been two fold.
Having worked in the frontend space for a while, I know there will always be a time where you will need to integrate a third party library. It could be for UI reasons like a map or a carousel that you don't want to build from scratch. It could also be for "product" reasons like integrating a third-party pixel or fraud detection provider.
As difficult as I make this sound in my head, this already happens even within my current workflow. Although I build react components, sometimes I have had to use the
window object to run some custom JS script that's outside of the paradigm. As long as it is narrow in scope, it should be okay.
Wouldn't you always have the burden of a runtime or a long compile time in excess? This has always been in the back of my head but this problem isn't new.
A slew of languages are built on top of the JVM - Scala, Clojure, Kotlin etc. but they seem to be thriving. No one set out to build another JVM - that is a solved problem but they can still optimize the "frontend" of the language with better syntax and grammar while retaining the safety of the underlying technology.
The current trend of compile to JS languages are following the same pattern. Yes there is an additional compile step and there is usually a runtime but by giving you a specific paradigm of programming, these languages are capable of providing elegant syntaxes and great developer experience. Having a compiler isn't necessarily a bad thing, especially if it's really friendly like in the case of Elm.
One of Elm’s goals is to change our relationship with compilers. Compilers should be assistants, not adversaries.
The additional runtime is necessary but can help improve performance and remain minimal. For example, immutability data structures can be optimized by implicit sharing. So when you duplicate the same array a few times in a compile to JS language, it still stores that data in the same memory location until it is actually changed. Even when it does, it can still share parts of the structure that haven't changed, thereby improving performance. This does require a runtime library in most cases, but projects like Purescript focus on avoiding the runtime altogether and projects like Rescript focus on blazing fast compilers.
The big appeal with Elm seems to be how it's designed for webapps and everything works within the same ecosystem - formatting, packages, templating. Especially templating, because in JS, we unfortunately reach to JSX for templating. Or something very unique to the framework like Svelte or Vue. I detest investing any time in learning templating because I feel like this skill doesn't transfer. We have been around the block with mustache, handlebars and JSX and everything does the same but in a slightly weird way. Like how there are no else statements in Mustache because they are "logic-less". You have to invert your "if selection" instead.
That's one of the main reasons I like Elm - it has been thought out and writing your UI is the same syntax as you would call functions in the language itself. That's powerful. And I'm impressed if someone has put so much thought into this small annoying piece of the development workflow, it really sounds like a well thought-out, UX driven language. I've listened to podcasts where people talk about Evan conducting user interviews on what people found most difficult in using Elm in the early days. That really speaks to me because I love iterating based on user feedback and used to conduct user interviews myself in a past life.
The only hesitation in going all-in on Elm is how the community reacts to the development model. It appears there's one bad article amidst several good indications but overall people don't seem impressed with how the team responds to criticism and provides updates.
The last thing I want to do is introduce a language to a team at work and have it constantly change in major ways or not push fixes for clearly known bugs for a very long time. I understand and accept how open source works. In fact, I also understand the whole BDFL and wanting to keep the language strictly within certain parameters - especially after showing so much evidence as to why that's a good thing. However, there is something nice about knowing when features and fixes will land, even if it's a year or two down the line. That's the kind of thing you can sell at your workplace and try to get everyone onboard.
Having authored exclusively in TS for past couple of years, I think I need an upgrade. I am grateful that it's such an exciting time to be in this space and we have so many good options available to choose from.