I find the constant conversation around code style extremely tiring.
I can't claim it isn't important. I do get the impression we think it is more important than it is.
I also think we frame things wrong. We push fp as being a declarative counter to imperative code. Feels more akin to switching coordinate systems. With so many examples of "look how easy this perfect sphere is in polar coordinates" when so many of us are working with rectangles. Or, at least, not perfect spheres.
But depending on the topic it's an absolute nuclear weapon. I've seen people accumulate pages of imperative code. Side effects everywhere, no reuse of small logical bits. 80% waste, averaging 4-6h per bugfix.
On the other hand short immutable code is more readable (yes even with a single letter vars), is linearly ordered, and often reusing the same combinators.
It’s hard to do FP in any language that isn’t designed for it. The reason for that is on a reasonably sized team you won’t be able to get consensus on adopting an FP style. There will always be the counter-argument that FP makes the code look weird, unmaintainable, unapproachable etc.
I think the only way to adopt it is to either use a language where it’s the default or get consensus from the team.
Otherwise you can sneak in bits here and there in a functional style, just don’t start implementing monads, functors, and Applicative. Anything beyond map and basic higher-order functions will scare the locals.
> It’s hard to do FP in any language that isn’t designed for it.
I don't see why this is true, and perhaps it's because I don't have a full enough concept of functional programming.
In any language, why can't we write functions that don't modify the arguments, offer the same return for the same arguments, and modify no internal state when called? And then compose those functions together to form a full working program?
> Otherwise you can sneak in bits here and there in a functional style, just don’t start implementing monads, functors, and Applicative. Anything beyond map and basic higher-order functions will scare the locals.
10 years ago you would have said the same thing about map and those "basic higher-order functions" that you say about monads, functors, and applicative.
I grimace whenever
I think about the time where I went a bit ham on FP as a junior engineer. I genuinely feel sorry for whoever is maintaining that piece of code.
That’s happening with OOP. I remember I picked up this codebase circa 2008 and this guy who worked on it before was learning OOP. Every little thing was a class, lots of pointless inheritance everywhere and nothing made much sense at all. Luckily the project was easy to scrap and rebuild.
Thanks for stating this so clearly. I am always confused why data flow frameworks, DSLs, or other syntactic sugar inevitably gets entangled with functional programming. Once more logic is in stateless functions and easy to test and compose (as you stated), one can gradually introduce layers, sugar, and abstraction (should the team choose)
On the contrary, that is exactly what those patterns are for, indeed it's the only legitimate justification for using them! If you can make your functions simple and stateless without using "fancy" patterns you should do so. The point of things like monads is to make it possible to do that with functions that do otherwise effectful things.
If your functions are "stateless" (by which I assume you mean they don't depend on or modify outside state), then they are pure functions so... that's exactly FP?
The linked website's CSS is unusably broken (at least in Chrome on Android): most of the text in example code snippets is white-on-white, thus invisible; and remains white-on-white even if selected.
Fortunately, there is a toggle to change theme in the upper right corner which at least makes things readable.
Is it just me, or does the bad advice format of the article make it hard to see tell the good advice is?
In my early days teaching LaTeX classes, I used to have an example of incorrect input in the first day’s material (forgetting to leave a space after a command). Even though it said before the example that it was incorrect, invariably, at least one person in each class would type it into their computer and have the error returned to them. I removed the example because it only hindered the teaching process. I feel like articles like this which use opposite-speak in making their point do the same thing.
It's a bit more analog, but one piece of advice I got in a teaching seminar was to only ever write true things on the board. This is important because students often zone out at just the wrong time and when they come back and realize they missed a bit of class, they'll glance at the board and furiously start copying down whatever you wrote without knowing the context. If it turns out what you wrote wasn't true, well now a whole bunch of students copied down the wrong thing and are going to be extremely confused why the example they copied verbatim from class isn't working.
The idea of writing point-free code in Javascript seems absurd to me.
On Haskell, the odds of a point-free rewriting increasing legibility are about as large of it reducing. And Haskell has all the syntax features that favors it. Javascript has none of those features.
Haskell level FP in TS is absurd on the whole. I respect the idea of fp-ts, and it's hardly the library's fault, but it is remarkably ugly. Type safety is only half the appeal of FP; it's also usually concise and pleasant to read. You lose that trying to hammer the concepts into a javascript shaped hole.
My general rule with point-free code is that it can be more readable when it's meant to convey that what's going on is a composition of components with no additional functionality.
These negative logic type blogs are such an annoying style of writing and very click baity. Obviously no one would want to lose functional programming at work on purpose, so why not just write a straight “How to Win…” article instead? Why make me have the cognitive overhead of reading the opposite of what you say?
This originated as a fun talk at the Auckland Functional Programming meetup. Given there is so much "here's how to get your team into FP" content out there already, this felt like an engaging approach and was a nice talk to share with folx.
I disagree that it's annoying and click baity — else I wouldn't have went to all the effort — but if it's not for you, it's not for you.
I didn't know what "point-free style programming" was so:
> Tacit programming (point-free programming) is a programming paradigm in which a function definition does not include information regarding its arguments, using combinators and function composition [...] instead of variables.
Note that in OCaml, you can't get too screwy with point-free programming because of the value restriction. It is possible to compose functions in a point-free manner, but those functions themselves have to have points if you want them to be generic. Standard example:
let last xs = List.fold_left (fun x y -> Some y) None xs
This is of type
last : 'a list -> 'a option = <fun>
Neat, `'a` is generic. Let's η-reduce out the `xs` and make the function point-free (ignoring the lambda):
let last = List.fold_left (fun x y -> Some y) None
This doesn't work the way that we want:
last : '_weak1 list -> '_weak1 option = <fun>
The moment that we call this weakly polymorphic function, its type is fixed and is no longer generic. In the toplevel:
# last [1;2;3];;
- : int option = Some 3
# last['x';'y';'z'];;
Error: This expression has type char but an expression was expected of type
int
Haskell, of course, is totally happy to let you do point-free mania with Kleisli arrows and all of the rest of it.
I like FP - I think that engineering and writing code in a way that would also let it be written in all the craziness of full FP style means you found the right abstraction - but I would never write it that way.
A nice example from the article:
const processData = composeP(syncWithBackend, cleansePII, validateData)
async function processData(data) {
await validateData(data)
const cleansedData = cleansePII(data)
await syncWithBackend(cleansedData)
return data
}
// or for the Promise-chainers…
const processData = data =>
validateData(data)
.then(cleansePII)
.then(syncWithBackend)
.then(() => data)
I would always write this as the 2nd option - it's always going to be the easiest to debug[0] and the abstractions it leverages are equivalent to the composed version in the first example or third example.
When I write code that leverages FP principles (pure functions, composition, immutable data structures, etc) I know I've found the right abstraction - but there's never a need to actually abstract it all the way. That's the job of a good compiler.
I'm nearly always writing code for other people to later debug, fix, extend and understand and rarely for the computer - don't make your future self's job harder than it needs to be.
On Chrome/Edge the page seems to open as expected and the PDF is previewed inline. On Firefox, a download immediately starts. Not a big issue or anything, just a slight difference in how browsers handle the page.
The HTML on the page responsible for this:
<iframe class="pdf" loading="lazy" src="/pdfs/2023-01-24-how-to-lose-fp-at-work.pdf" title="How to Lose Functional Programming at Work - PDF">
</iframe>
Here's approximately what I've used myself in the past as an alternative:
<object data="/files/my-document.pdf#zoom=110" type="application/pdf" class="my-style-class" title="My PDF document">
<!-- Fallback for older browsers that do not support the object tag -->
<embed src="/files/my-document.pdf#zoom=110" type="application/pdf">
<!-- Fallback in case PDF display of any sort is not supported -->
<noembed>
<span class="my-warning-class">
It seems like your browser does not support displaying PDF files.
You can download the file separately <a href="/files/my-document.pdf" download>here</a>.
</span>
</noembed>
</embed>
</object>
(not too clean of a solution, but seems to work okay in most cases)
The presentation/article itself is pretty nice, though. I really like the mentions of the human aspect of it all, how getting others onboard is quite important!
That's really weird, and I'm sorry that happened. I'm on Firefox Developer Edition on macOS, and it displays inline for me, but that could be my settings.
I'll take a look at using an embed tonight. Thanks for the feedback!
It’s always a terrible idea to go against the ergonomics and idioms in a language. Shoehorning JavaScript into something purely function is just as bad of an idea as trying to do object-orientation in Haskell. If you believe in certain patterns, pick the right tool—in this case a compile-to-JS language—for the job. Either make the case for rewriting certain modules, or find a job/team that supports your goals and principles.
I don’t think I’ve ever thought a blog post—not its author, just the post itself—is a jerk until now. I read most of it but bailed because it felt like being bullied for no apparent reason.
Wow, I'm horrified that the post was received this way. How did it make you feel bullied? Was this because of it using imperatives with "do" and "don't"?
edit: the real-talk takeaways at the end are worth reading, I think (I'm biased, though)
TS and Elm were included in a "Don't have static type checking" section, alongside Flow, ReasonML, and a blank space for all the others. The point I was going for was that there are numerous options for static type checking for the web out there.
[+] [-] taeric|3 years ago|reply
I can't claim it isn't important. I do get the impression we think it is more important than it is.
I also think we frame things wrong. We push fp as being a declarative counter to imperative code. Feels more akin to switching coordinate systems. With so many examples of "look how easy this perfect sphere is in polar coordinates" when so many of us are working with rectangles. Or, at least, not perfect spheres.
[+] [-] agumonkey|3 years ago|reply
But depending on the topic it's an absolute nuclear weapon. I've seen people accumulate pages of imperative code. Side effects everywhere, no reuse of small logical bits. 80% waste, averaging 4-6h per bugfix.
On the other hand short immutable code is more readable (yes even with a single letter vars), is linearly ordered, and often reusing the same combinators.
[+] [-] ilyt|3 years ago|reply
[+] [-] agentultra|3 years ago|reply
I think the only way to adopt it is to either use a language where it’s the default or get consensus from the team.
Otherwise you can sneak in bits here and there in a functional style, just don’t start implementing monads, functors, and Applicative. Anything beyond map and basic higher-order functions will scare the locals.
[+] [-] grugagag|3 years ago|reply
[+] [-] CTmystery|3 years ago|reply
I don't see why this is true, and perhaps it's because I don't have a full enough concept of functional programming.
In any language, why can't we write functions that don't modify the arguments, offer the same return for the same arguments, and modify no internal state when called? And then compose those functions together to form a full working program?
[+] [-] lmm|3 years ago|reply
10 years ago you would have said the same thing about map and those "basic higher-order functions" that you say about monads, functors, and applicative.
[+] [-] user3939382|3 years ago|reply
[+] [-] creakingstairs|3 years ago|reply
[+] [-] pharmakom|3 years ago|reply
[+] [-] grugagag|3 years ago|reply
[+] [-] muraiki|3 years ago|reply
Edit: A good book: https://en.m.wikipedia.org/wiki/Higher-Order_Perl
[+] [-] adamkl|3 years ago|reply
This can be done in any language without introducing “foreign” FP patterns and instantly makes code easier to understand and test.
[+] [-] CTmystery|3 years ago|reply
[+] [-] lmm|3 years ago|reply
[+] [-] Tainnor|3 years ago|reply
[+] [-] robertwpearce|3 years ago|reply
[+] [-] tetromino_|3 years ago|reply
Fortunately, there is a toggle to change theme in the upper right corner which at least makes things readable.
[+] [-] robertwpearce|3 years ago|reply
[+] [-] dhosek|3 years ago|reply
In my early days teaching LaTeX classes, I used to have an example of incorrect input in the first day’s material (forgetting to leave a space after a command). Even though it said before the example that it was incorrect, invariably, at least one person in each class would type it into their computer and have the error returned to them. I removed the example because it only hindered the teaching process. I feel like articles like this which use opposite-speak in making their point do the same thing.
[+] [-] sweetjuly|3 years ago|reply
[+] [-] kagevf|3 years ago|reply
[+] [-] 12345hn6789|3 years ago|reply
1. Nobody who knows F paradigms is joining. Also these people most likely won't want to learn either.
2. There will be a constant battle for all PRs. "What is this, what is a filter doing, why are we mapping when we could just for loop and break"
If you have even an inkling to do FP, your only option (besides building your own team) is finding a company that respects it
[+] [-] mLuby|3 years ago|reply
[+] [-] mb7733|3 years ago|reply
[+] [-] robertwpearce|3 years ago|reply
[+] [-] marcosdumay|3 years ago|reply
On Haskell, the odds of a point-free rewriting increasing legibility are about as large of it reducing. And Haskell has all the syntax features that favors it. Javascript has none of those features.
[+] [-] jim-jim-jim|3 years ago|reply
[+] [-] pklausler|3 years ago|reply
[+] [-] xwdv|3 years ago|reply
[+] [-] robertwpearce|3 years ago|reply
I disagree that it's annoying and click baity — else I wouldn't have went to all the effort — but if it's not for you, it's not for you.
[+] [-] psnehanshu|3 years ago|reply
[+] [-] baby|3 years ago|reply
> Tacit programming (point-free programming) is a programming paradigm in which a function definition does not include information regarding its arguments, using combinators and function composition [...] instead of variables.
from https://stackoverflow.com/questions/944446/what-is-point-fre...
I guess it's the fact that in programming languages like OCaml you write functions like that:
and so you can partially apply them:* using `some_fn` without any argument is manipulating a function with two arguments
* using `some_fn arg1` returns a new function that only takes one argument
* using `some_fn arg1 arg2` applies the entire function
[+] [-] omegaham|3 years ago|reply
[+] [-] ourmandave|3 years ago|reply
[+] [-] bern4444|3 years ago|reply
A nice example from the article:
I would always write this as the 2nd option - it's always going to be the easiest to debug[0] and the abstractions it leverages are equivalent to the composed version in the first example or third example.When I write code that leverages FP principles (pure functions, composition, immutable data structures, etc) I know I've found the right abstraction - but there's never a need to actually abstract it all the way. That's the job of a good compiler.
I'm nearly always writing code for other people to later debug, fix, extend and understand and rarely for the computer - don't make your future self's job harder than it needs to be.
[0] https://sambernheim.com/blog/debug-driven-development
[+] [-] kagevf|3 years ago|reply
“balking”?
[+] [-] KronisLV|3 years ago|reply
The HTML on the page responsible for this:
Here's approximately what I've used myself in the past as an alternative: (not too clean of a solution, but seems to work okay in most cases)The presentation/article itself is pretty nice, though. I really like the mentions of the human aspect of it all, how getting others onboard is quite important!
[+] [-] robertwpearce|3 years ago|reply
I'll take a look at using an embed tonight. Thanks for the feedback!
[+] [-] toastal|3 years ago|reply
[+] [-] eyelidlessness|3 years ago|reply
[+] [-] robertwpearce|3 years ago|reply
edit: the real-talk takeaways at the end are worth reading, I think (I'm biased, though)
[+] [-] yakshaving_jgt|3 years ago|reply
[+] [-] robertwpearce|3 years ago|reply
[+] [-] combinator_3|3 years ago|reply