Mostly adequate guide to FP (in JavaScript)
mostly-adequate.gitbook.io
mostly-adequate.gitbook.io
If functional programming is so great, it should be able to stand on its own merits without the constant insults thrown at other programming paradigms.
I lean more towards FP than OOP but there are times when each paradigm makes sense in a specific situation (especially because we rely on a lot of third party code we can’t control).
> Who on earth would craft such a ghastly abomination?
> It may come as a surprise to hear that we can write full, everyday applications along the lines of the functional analog above.
> It is obnoxiously verbose and, as it happens, bad practice
> I avoid using this like a dirty nappy. There's really no need when writing functional code.
> If you are the micro-optimization sort, please close this book. If you cannot get your money back, perhaps you can exchange it for something more fiddly.
To be fair, the later chapters are much more focused solely on FP without the disparaging comments toward OOP.
A summary is available in: https://www.info.ucl.ac.be/~pvr/VanRoyChapter.pdf
One of the running themes is the paradigm paradox: "More is not better (or worse) than less, just different".
In other words, each paradigm has its own distinct advantages, which are discussed both in practical terms and using formal semantics.
There is no shortage of drier materials on the subject!
So how does this come across in my tutorial writing?
Not at all. That part of my personality is completely absent (I hope) from anything I create that is intended to teach people. Because the people I want to teach programming to could be anybody. They could be someone who can barely speak English and will just be totally confused by snark. They could be a precocious ten year old whom I would rather not expose to my adult cynicism. They'll get enough of it in life anyway.
Teaching materials should be clear, cynicism and snark free, and should never be condescending to either the reader or any alternative technology or point of view. That doesn't mean criticism free. But the criticism should feel balanced. Does comparing the alternative with a dirty nappy feel balanced to you?
I was merely describing what I thought the author was trying to do. I wasn’t necessarily suggesting we give them a medal for style.
This being said, if you understand the author’s intention, it’s much easier to focus on the substance of the text, which IMO is the more important part here.
In that case we're back to the original criticism which is that proponents of functional programming have a marked tendency to be snarky and condescending towards other programming paradigms and that (regardless of whether they are right or not) this is weird and off-putting to people who just want to learn what functional programming is and make up their own minds about it. Every group of people develop a culture and for some reason the group of people who are into FP have developed a culture of condescension and self righteousness (+). That's certainly worthy of criticism. This piece of writing would be better off without dirty nappy references and if they were absent, we'd be discussing the content rather than the tone. Or possibly even just reading and learning from it which I have to assume is the author's intention.
(+) Of course not all of them, and I have read through the introduction of this book and it's not the worst in this regard. It's just frustrating is all.
But I read through the first 4 chapters, and I personally did not get a whiff of condescension. Is it possible that people are projecting their insecurities into a perceived slight?
I also constantly hear this refrain from “FP outsiders”, but I’ve been obsessed with FP books and journal articles for the past couple years, and I really don’t see “the FP community” (if that’s really one thing) the same way you do.
I’ve found that when I approach people with even the silliest of questions, they will bend over backward trying to give me a good answer, they will be happy that someone wants to talk about what they love, and personally I have found most people in these circles to be monstrously smart.
In my case, I don't think so. I don't have any strong opinion on the topic of FP. I do have strong opinions about writing style in tutorials though.
However, rather than characterizing it as insecurities, I think you could say people are projecting their prior experience with FP proponents and being harsher in their criticisms because of that.
It's something for the writer to be aware of. Every topic will come up against preconceptions. If you write about quaternions, for example, you'll need to address the preconception of "quaternions are hard to understand". All math writing has to address that on some level actually, unless it's directed to math experts. Likewise, writing on FP has to deal with the preconception that FP proponents are condescending to other programming styles.
And by "deal with" , I don't mean "directly address", although that is an option. I mean that you need to keep it in mind while writing so that your audience gets the value you intend from your work.
I don't. There are lots of good functional programming resources where the author is polite and civil. Being condescendent is not an attribute of functional programming.
Example: https://fsharpforfunandprofit.com/
I've written Node for a living. Mostly Typescript in recent years. I've encountered multiple codebases where previous developers have used all kinds of novel constructs to make Javascript codebases resemble a purely functional language. I've never seen an example of this where the developer has actually managed to make their codebase more concise, understandable, testable, extensible, or more robust. The usual outcome is a complete birds-nest of spaghetti code that only the original developer could ever understand. These codebases usually never outlive the tenure of the original developer: They're usually thrown out the second another dev even lays eyes on it.
Reading through this article, I don't really see anything that would make my real-world coding job easier. I don't see any constructs that would actually make my code less complicated. Not to mention the elephant in the room that adding thousands of lines of scaffolding code (that only the author understands) so that Javascript supports monads (that the developers asked to maintain the code won't understand) adds so much more surface area for bugs. If you want to write an application in Haskell, just do that instead. At least then the company knows to look for a Haskell developer to maintain the mess you've made.
And, if the author is successful, then the chances that you could one day be able to write JavaScript code in this fashion and expect it to be maintainable would increase!
This is almost purely functional but makes no attempt to look like anything other than JavaScript and just about everything is identifiable to profilers and covered by some form of test automation.
Likewise declarative does not necessarily mean functional. The examples you mention are declarative but not explicitly functional.
I get the impression people come to these statements because they read something about functions somewhere once. When you get past the vanity and actually read the code it’s just a bunch of functions and no vanity.
I've really enjoyed creating functional pipelines with Ramda in the past for professional projects. I liked how I could use the Ramda functions to explicitly state in my code what the flow of data was with functions like pipe and converge. It seemed to me that being able to understand the dataflow was easier with this paradigm. I could even create pipelines that would automate away dealing with promises in my pipelines with pipeWith. I would implement the same bits of code in "vanilla" js and with Ramda and Ramda was more concise and easier to read (if you understood how Ramda worked...).
You can see an example of the style that I like here: https://github.com/chughes87/calendarbot. I definitely was more "clever" in parts of that codebase than I let myself be in a professional setting heh.
I successfully onboarded a different team onto one of my projects when I was being switched to a different product at my company. An engineer who later did some maintenance work on it told me that the codebase was simple and easy to work with. I did get complaints about a later project that I implemented with Ramda from a person who was totally uninitiated and didn't bother to ask me for help..
I made a lil presentation about Ramda that explains some of this with some graphics that I think are helpful: https://docs.google.com/presentation/d/1tmre_8qJP-QhakXbiBpZ...
There's a lot more to developing large projects than your own code. What about the ecosystem? What about everyone else's code? JS IMHO is just a complete mess. That's not at all to belittle the size of the problems it is tasked with solving, which are hard and complex. The difficulty is precisely why the right tool for the job is something that really insists on some level of correctness, in the vein of what rust tries to do at the systems level.
This is all IMHO and there's a lot of room for different opinions here, but I'm guessing we have a consensus, even among JS's biggest advocates, that it can't be described as "insisting on correctness".
Unfortunately the more relevant follow-up question might be: okay it's the wrong tool for the job, so what? It's what we have.
JavaScript's ubiquity has everything to do with its monopoly in the browser, and nothing to do with any specific features of the language.
But Javascript has grown into a language that makes some solid and unique trade-offs including its simple single-threaded concurrency, modern language features, async-everything, first-class Promise, and Typescript.
"Javascript sucks and people only use it because they have to" is both wrong and boring. We, as a community, have to stop trotting out this tired comment any time a submission has the word Javascript in it.
Single-threaded + async-everything is a unique and powerful feature of Javascript. You might not like it every time, but it's useful most of the time. Most other languages make it easy to write single-threaded but blocking code where you need to reach for an extra solution to write async code, and not everyone needs to even use the same solution, and it doesn't necessarily work with the default blocking ecosystem.
We take that for granted in Javascript.
Once again, this is a very tired thread. Sometimes you just have to admit there are trade-offs and that you aren't going to have a taste for every decision on every trade-off every time. And that's okay.
Nobody in this thread is even interacting with TFA.
I agree with above comments that you could have taken any language. But you have a point, making async mandatory is a powerful thing.
This could have been done to any language tho, Java, TCL, Scheme, whatever.
IMO Tcl would have been a vastly preferable choice for a browser scripting language. Text is its native data type, and would have minimized impedance mismatches with other functional areas of the text-based HTML/HTTP environment. Also it would have been far easier for newbies to get started with web script hacking. At the time JavaScript seemed like alien algebra to a lot of non-computer science majors.
If you look at the post I replied to, I was countering the idea that "JavaScript must be good because lots of people use it". JavaScript is popular today because it was popular yesterday, and the roots of that chain is JavaScript was popular in late 90's because it was your only real choice.
I've used actually bad languages professionally. JavaScript today is merely mediocre, thanks to nearly 30 years of fixing. But it's still held back by its roots of being kinda awful. There are unambiguously better choices for non-browser codebases, unless "whatever is popular" is a primary driver.
I totally get this sentiment because I feel it myself with some topics. But to give you another perspective: the comment and issue keeps coming up because in the eyes of some (many?) the problem hasn’t been solved.
It’s like I’m getting pin pricked every day so I keep complaining about it.
I'm not sure how someone's statement of personal motivation can be wrong? Here is mine: JavaScript doesn't suck. However I personally do "only use it because I have to", i.e. because of the browser support. Nothing more. Where's the "wrong" in that? I'm not lying to you. I promise.
And JavaScript isn't alone! There are many more languages I think are simply okay, and don't suck. Several of those I have used professionally because I had to, but would not choose them for a personal project. I would also use them if they were all a web browser ecosystem supported.
And just because something is ubiquitous doesn't mean there doesn't exist anything better.
Businesses/industries being huge does not indicate whether a tool/method/approach is high-quality.
Terminal apps, trading algos, operating systems, compilers, embedded, databases, etc etc.
JS is never the best tool for the job. But sometimes, it's the only one.
1. Its maintenance/activity appear sporadic at best. 2. It's inscrutable. Whenever I've had issues, I don't have any idea even how to approach solving them. Half the time they reference in-depth mathematical terms that just are not relevant to anyone who isn't implementing the language 95% of the time. 3. The tooling often just... doesn't work. I'll go to run a commend given in the official tutorial, and it fails in a way that is just beyond me, as an experienced engineer.
TBH, I'd really love to use it. I've been finding myself using `fp-ts` on many of my projects for just such a reason, and have even set up `unplugin-auto-import` to automatically detect and import those modules, so it's like I have more in my stdlib. I've even thought of making a true language out of these primitives.
what I really detest about javascript is its inability to say no to the programmer (most dominantly typing woes), and how incredibly late it got some super basic features for code organization. private class members (in a way that isn't syntactically insane) got added to the language figuratively two days ago. what the hell?
Is it crazy? yeah. But it’s not quasi functional.
I thought Eich did?
this was pretty much the result of the XHTML debacle as well, and I know the reasons why that went down the way it did, but it's kind of weird to me that We Just Can't Have Enforced Correctness In The Browser.
It's far from being "the standard language for the browser", but the browser doesn't know that.
It's easy to understand Lists, Options, Eithers and all the other classic monads and what they do. It's harder to understand other forms this can take.
At work I had to build something that ended up leading to creating a new monad type[0]. That process crystalized why we ended up with these ideas and structures much more clearly.
I also highly recommend any of Scott Wlaschin's videos[1]. He does a great job conveying FP ideas, and his videos introduced me to F# which is a really fun language with a very clean syntax.
Another great blog is by James Sinclair [2] who similarly has several articles on using FP in a practical way though some of the code can get a little deep but in an interesting way.
Loosely coupled but cohesive is a very useful mantra when integrating FP ideas along with keeping everything very simple - avoid crazy compositions, deeply nested types, etc. Just cause something can be abstracted due to FP (composing a bunch of function calls, looping once instead of 3 times etc) doesn't mean you should. There is value in breaking pieces up.
[0] https://sambernheim.com/blog/building-a-monad
[1] https://www.google.com/search?client=safari&rls=en&q=scott+w...
Allowing a chain of fat arrows and parentheses-free parameters was one of the nicer choices they made for ergonomic functional programming — being able to concisely write:
const add = x => y => x + y;
Ends up looking similar to Haskell type signatures.
I know there are proposals but neither seems to be making much progress.
I like FP but shoehorning it in with libraries is ugly compared to having native syntax.
https://github.com/tc39/proposal-pipeline-operator - Stage 2
https://github.com/tc39/proposal-pattern-matching - Stage 1
Hopefully we get both in the next couple of years.
Multiple colleagues swear by this book in particular, but I don't know if it needs to be read cover to cover. Reassuringly enough, much of the foundational content regarding immutability and higher order functions seems like it is already common knowledge to younger devs.
I think the biggest conceptual leap from the FP lite that is already practiced in modern JS to the "hard FP" of Haskell and Scala is the generalized approach to contexts via functors/monads. Luckily one such context already exists in JS in the form of the list. Implementing Option/Maybe using a single item list, and composing operations using the existing map and flatMap methods is a nice exercise that paves the way to the happy path only style of programming of the more advanced langs.
Javascript can do some functional programming, but it's not Haskell or OCaml. If you try to use it like that it quickly becomes a big mess and one that is not performant at all. You want to do pure, functional programming? Then write Haskell, or Elm, or Purescript.
I'm saying this as someone that loves fp, but is trying to get rid of a considerable chunk of fp-ts on a big codebase at work.
As a wise man once said, don't fight the language. Doing this deviates from Javascript semantics. It's a hack that is not actually helping people learn fp.
Also, please, don't do monads in Javascript! Monads are a solution for pure languages to deal with effects. Javascript can just do effects as it is!
I haven't had occasion to use wasm but it seems that it provides the ability to run most (all?) languages in the browser.
Here, for example, is f# wasm.
Are there any wasm demos (not necessarily source code) to try that would blow my mind? Genuinely interested. Maybe I have seen dozens and it's not obvious.
The only way I can see the problem (assuming someone agrees it is) of JS getting solved is if something comes along that's so amazing and blows it out of the water so hard that adoption explodes and browsers start natively migrating to it, along the lines of what we've seen with TypeScript, but instead of a bandaid a full replacement.
If something else comes along, gains a lot of traction, and develops its own ecosystem then javascript could conceivably eventually just fade into the background. But that's going to take time.
Enjoy:
- record and array literals
- arrow syntax for lambdas
- spread operator
- map, reduce, forEach
- string template literals
- default values with ||
- single thread memory model
- all the pretty colours
Avoid:
- Formal OO constructs, i.e. 'class' and whatever goes on inside it. They feel out of place, and e.g. the this.function() syntax is clanky. Special hate reserved for those magic proxy getters - breaks the simple record model.
- Formal typing, i.e. Typescript. Becomes unnecessarily verbose and boilerplated, tooling is not quite there, and you almost always need to poke holes in the type system to do anything interesting anyway.
- Lodash and friends. Not needed now the core language has so much out the box.
Where Javascript seems to shine is in being a simple, functional language, with concise syntax, and without heavy OO or type formalisms.
At least to me, Lodash is absolutely necessary even in new projects — such a wealth of functionality and most of it isn’t available OOB in the standard library. It’s easily tree shakable as well.
As for formal typing, TypeScript was a boon for my productivity. Curious about any examples of use where it’s been inadequate?
I can’t tell you how many times I see “can’t call function toLowerCase of undefined”, etc.
“but Typescript!”, doesn’t do runtime type checking.
I very much prefer defensive programming. Assume nothing.
Think that should be addressed by optional chaining now.
I'm also a fan of "class" since it makes the deeply-embedded-but-awful OO system actually usable without twisting into a pretzel or engaging in a whole lot of "OMG why, why did you do that?".
Occasionally it is necessary for structures to act polymorphically, thence it is but a simple matter to put a function in the structure for that behaviour (maybe with a reference to the enclosing structure in scope)
Typescript is another language layer, devs will tend to write even more code for a given problem - often not helpful. It should be possible to do a lot of static type checking without annotations.
That "even more code" is communication. It's documentation that you ought to be recording somewhere anyway, for the most part. The nice part about using TypeScript for that particular documentation is that then your tools can help you with both the reading and the writing.
TS is helping somewhat but it compiles down to JS, and well, almost anything can happen at runtime.
“Compiles to JS” doesn’t imply anything about what a language has to look like; see PureScript for example.
Many of them seem to be about what I, the developer, can use.
Let me reframe it — what if you thought of FP techniques as something you could expose to a user of your API?
What if you viewed all your work in a language as a language. Borrowing concepts like affine types (aha, rust!), dependent types (hello, Agda!), composition (from pipes to combinators, this one is everywhere!) is important.
Strictly procedural or OO concepts might be useful in an implementation, but it rarely helps the user.
Some people writing security vulnerabilities in C are feeling put off by a programming language with sanity checks.
One's toolbelt doesn't ever have enough tools.