102 comments

[ 6.4 ms ] story [ 191 ms ] thread
I architect my code in layers. Generally OO based then specifically functional based; I find that works best for me.
You should do whatever works for you! But, have you encountered the idea of "Functional core, imperative shell?"

https://www.javiercasas.com/articles/functional-programming-...

i think the original talk by Gary is basically perfect for this bc it shows the power of mixing FP and non-FP in an imperative but flexible language (ruby)

it's... a little different in Haskell bc it basically makes you work in this paradigm already, so not a huge value add imo

all that is to say, just watch the original talk:

https://www.destroyallsoftware.com/talks/boundaries

Not sure that everything should be "OO core".

When I look at architecture, often some entire components can be viewed as a FP-style function. Adding the code to make it behave so is well worth it for the long term benefits.

If you start out writing this module as a class you instantiate, it can make the whole component more stateful as it evolves -- classes naturally push towards more stateful code.

Overall I think OO, FP and simple procedural programming should be at the disposal of everyone.

Just that historically the last ~20 years of enterprise programming (with Java, C# and OO-heavy C++ code) have really outsized OO's influence compared to how often it's the right tool

Completely agree. There are a couple of "killer features" of functional programming that led to us adopting it both to build Dark, and for Dark itself. Immutable values makes it so much easier to reason about programs. And then removing null and exceptions.

The downsides: a bit of a learning curve for programmers used to OO; some classes of problems are easier with OO, though not as many as you'd expect.

The real downside I've seen is that so much valuable information is in academic papers that aren't approachable.

> The real downside I've seen is that so much valuable information is in academic papers that aren't approachable.

They become more approachable the longer you spend reading papers, but overall I definitely agree with you. Lots of papers just assume too much of the reader, which means you've gotta read like six other papers to find out what's really going on in this one.

As someone that likes functional principles but hasn’t found a simple functional language with good IDE support, I’m more worried about an approachable language than approachable papers.

Hoping you’re successful in helping to solve this.

> FP would need to solve a severe problem that could not be solved with existing approaches in order to make a breakthrough

So the question the author is asking is whether there is problem which can only be solved via lambda calculus and not by turning machines or at least the difference should be significant in favour of lambda calculus.

Since both approaches are equivalent models of computation, I have to bet on the "no such killer app" side.

It's not "can't solve" in the sense of abstract computation, but rather "can't solve" in the sense of "you couldn't build facebook in the brainfuck language."
Lots of words without much value, just like FP!

Seriously, why is this on the homepage? Doesn't contain anything interesting about FP.

Actually you are usually writing much less code with FP approaches ;-).
Clojure is an FP language. Clojure is relatively terse.
>Lots of words without much value, just like FP!

not sure if

a) people didn't get the pun

b) the pun wasn't intended

or c) both

:thinking:

I don't get the pun. Could you explain?
Immutability is important in FP, lots of functional languages don't even have a var-keyword - they don't deal with values in the sense that oop or imperative languages do.

(Instead, they just functionally transform shallow copies of input data, iirc this paradigm is called 'data driven programming')

...so, yeah, "no values" relative to the amount of words used in FP. The pun needs a bit of a stretch, but I'd take it ¯\_(ツ)_/¯

It's a bad pun, if it was meant as one. FP is all values and few words, compared to OO languages.
meh, to me the term "value" only makes sense in a mutable context - if the variable can't be mutated, it is it's own value. but let's not get lost in semantics over a joke (the more because we don't even know wether it was intended)
> to me the term "value" only makes sense in a mutable context - if the variable can't be mutated, it is it's own value

I'm so confused by this haha.

A value is a term in a language's grammar that cannot be further reduced by the semantics of that language.

In some OO languages, objects may be values but functions or types may not. (Though this has been changing lately as more OO languages are getting on board with higher-order functions, for example.)

In most FP languages, functions and types are also values. In the lambda calculus, two out of the three possible terms are values. In the pi calculus, types become values (and, therefore, values become types).

This is where I was going with my previous comment: FP languages tend to have a wider variety of "values" than the OO languages, which instead just have lots of extra core forms in the language that don't directly translate to the values of the language's semantics.

I am not sure if you have been paying attention to the strongly typed, category theory zealots lately (who seem to claim they hold the one and only valid functional programming viewpoint). The size of vocabulary and relations they end up juggling put any over engineered OO system to shame.

It is attracting the same kind of people that 15 years ago would have reached for (and preached) the GoF book.

> I am not sure if you have been paying attention to the strongly typed, category theory zealots lately

Well (1) this is not inherent to all functional programming, and (2) the joke appears to imply that code written in FP will be more verbose with less content, which is surely not the case. (And also (3) I'm guessing you meant "statically typed" instead of "strongly typed", since the latter is poorly defined and not generally the subject of discussion among functional programmers that I've interacted with.)

I also have met quite a few people who are into category theory, and none of them have made any claim about holding "the one and only valid functional programming viewpoint". But the people I talk to are genuine academic researchers and not armchair academicians, so perhaps there's a difference there.

You are right on all points.

As for the category theory zealots I have found at work or at conferences, none of them were academics, but rather what I would describe as clueless narcissists overdosed on FP Kool-aid.

Ah yeah, that's the unfortunate part of those communities haha. But every community has some of those. :)

When you say "conferences", do you mean academic conferences or industry/language-specific conferences?

I found that there were plenty of people deep into category theory at ICFP this year (an academic conference), but most of them had very reasonable perspectives on the utility of CT and things to that effect.

Isn't FP simply too esoteric to ever become properly mainstream?
You can get 98% of the benefits of FP with 0% of the category theory.
You can also get many of the benefits of category theory without learning any of the category theory. :)
No, definitely not. FP concepts are catching on in mainstream languages. Lots of languages now support optionals instead of implicit nulls, maps and filters over lists, higher-order functions, etc. These all originated in FP and have just made their way over to the more mainstream imperative languages.

Not only that, but FP is must more a state of mind than a set of language features. You can write functional code in practically any language, really, although some of them will make it easier than others.

Looking in from the outside, I just can't see how a project written in most esoteric-leaning languages can scale beyond like 5 developers without becoming an unreadable mess simply due to the expressiveness of the language.
> I just can't see how a project written in most esoteric-leaning languages can scale

Well what do you mean by "esoteric-leaning"?

It seems like you just mean "languages I'm not used to", which is a very limiting perspective, but perhaps I've misinterpreted you here.

Obviously nobody thinks you should write your production code in Brainfuck (which is an actual esoteric language).

But there are plenty of places that use functional languages in production. Functional language are not esoteric by nature — they're just different. It's like calling SQL an esoteric language just because you're used to Java.

Jane Street uses OCaml for everything, Facebook uses Haskell and ReasonML (which is really OCaml), Galois uses Haskell, Microsoft has F# and F* and a Haskell group, GitHub uses Haskell... There are plenty of examples of functional languages in industry. They're not esoteric, and they do scale when implemented correctly (same as anything else).

> without becoming an unreadable mess simply due to the expressiveness of the language.

...?

I don't mean this rudely, but are you sure you know what "expressiveness" means? More expressive languages are not inherently more or less readable than other languages. They simply enable you to do things you couldn't do in those other languages.

C is more expressive than, say, x86 assembly by the inclusion of features like types. Do types make your code less readable? I don't think so.

Java is more expressive than C by the inclusion of classes. Do classes inherently make your code less readable? I don't think so.

Haskell is more expressive than Java by the inclusion of higher-kinded types. Do HKTs inherently make your code less readable? Not if you know what they are and how to use them — which you would if you use a language that supports them. So I don't think so.

FP shouldn't be thought of as orthodox Haskell.

It's more about the higher level concepts of having stateless code and pure functions where you can and isolate the stateful/impure parts.

You can use these design techniques in any language you want.

I consider FP to just be one of the tools in my programming toolbox. And apply it where it will fit best. Because not every problem should be solved with FP, nor with OOP for that matter.

Though it is sometimes educational to apply only a single solution to all problems. Just to see how far you can stretch the usefulness of the tool.

A nice talk about where (and where not) to apply FP is this talk by Gary Bernhardt: https://www.destroyallsoftware.com/talks/boundaries

So true. Generally, whichever one best matches the feeling best is how I go.

Some things really feel like objects, they've got little personalities, friends, parents... a whole list of talents and characteristics. OOP it is.

Other things are more like physics. It doesn't really need to have a name to exist, there doesn't need to be a container, it always acts predictably. Time to get functional.

I've also been using a tactic which I have no idea what it's really called, but I call it augmentation. I think of them like those crystals you add to your weapons in diablo or other RPGs. The gist is: a public readonly member which takes the object that holds it as an argument and has extra functionality. So like:

``` class Staff { public readonly flamePower = new FlameAugment(this); } (new Staff()).flamePower.doSomethingSpecialInvolvingStaff(); ```

Wouldn’t that just be a form of inversion of control? It feels a lot like dependency injection, though maybe I’m misunderstanding from the example.
Definitely like a form of inversion of control. Wouldn't think to call it that because the inversion is so shallow, and the control is always accessed from the context of the typical controller. It doesn't feel like what I use IOC for, though there is a similarity.
FYI: Code markup on HN works with two spaces at the start of the line, your example is probably meant to look more like this:

  class Staff {
    public readonly flamePower = new FlameAugment(this);
  }
  
  (new Staff()).flamePower.doSomethingSpecialInvolvingStaff();
Isn't this basically what an Entity Component system is?
Bingo. Just looked it up, and that looks like exactly what I'm talking about. I can't say for certain as I haven't ever used/read code that was described as an Entity Component system, so there may be some crucial differences I'm overlooking. But I'm pretty sure you nailed it.

EDIT: Just read into this a bit more (http://vasir.net/blog/game-development/how-to-build-entity-c...). It's something different. Kind of a mix between this and IOC.

I think that you mean the Decorator pattern
It's like decorator. My experience with decorators are that they modify prototype, which is something I'm not a fan of. They also have a tendency to create too many layers, like overused inheritance.
This way of doing mixins is nice, reliable, testable way of reusable logic and works well with structural type system. I think going this obvious way would be better than hooks for React. We will see.
This is why I like Scala, the best of both world, FP + OOP
> I consider FP to just be one of the tools in my programming toolbox.

This is a healthy attitude to most paradigms. It's important to understand things from different perspectives because that enables us to frame problems in the correct fashion. If you only know C or other procedural languages, for instance, and are faced with a decision problem that is naturally expressed in a few lines of Prolog, you may end up writing a large chunk of Prolog to solve your problem. On the other hand, if you only know Prolog, you can solve the problem quickly, but may not be able to write a specialized program in C that executes that solution quickly enough for your target application.

Python is kind of a strange beast - definitely imperative but with some FP-ish features: functions first-class citizenship, list comprehensions, generator functions/expressions (and there is the functools module). It is gaining more and more native immutable collections with each release. This multi-paradigm approach is what makes it one of the best glue-languages out there.

Python lacks tail call optimizations and recursion dept is limited to ~1000, so if your algorithm is not O(log n) or better you may have to convert from recursive to iterative (there is a recipe that makes conversion trivial) but other than that I'm content with its FP-style features.

I guess many beginner developers haven't realize this feature of Python yet. There are a couple of lib to enhance the FP feature of Python. Like itertool, functool, maybe more. In PySpark there are many functions take other function as parameters.

Another language is JavaScript. It uses function as parameter all the time but often just one time but not in a general way. Seems no JavaScript developer really seriously care about the term FP or OO.

>Seems no JavaScript developer really seriously care about the term FP or OO.

Oh no, they care. The reason it doesn't seem like FP is big in the web dev world is because of reactive programming paradigm.

Reactive programming paradigm is designed so when one part of the program is processing it doesn't lock up the UI elements. This defaulting to being thread safe and lock free comes from the FP world.

Reactive programming is a marriage between functional programing and procedural programming paradigms and is incredibly popular. I suspect it is far more popular in the front end world than FP is in the back end world, showing their adoption, despite different, is stronger.

--

On the backend side of things, many of the popular languages have been slowly gaining FP toys, not just Python. C++, Java, Scala, and so on..

Agree. In my previous project due to very tight schedule I had to find a better way to generalize the models which ended up using a lot of FP way in addition to OO way. In the project I was using Groovy which I didn't explore its FP potential before. Then recently I began to read Scala(A similar language but might be better) books and take course. I've used Scala but not very much. Because of pressure of the previous project now I understand how useful that abstraction can deal with so many problem beautifully by generalization of common patterns.

FP Makes Everybody Think Hard. Go METH! (Andrew Yang want to Make American Think Hard)

wrt Picking and choosing, I think it's still possible to write code in an "FP" style (even just aesthetically) whenever possible or within (say) an OOP program e.g. Abstract Syntax Trees map very well to OOP but the processing of them is very good for functional programming.

For example, I write in an SSA-like style whenever possible i.e. no variable reuse unless declared in loops. Keeping programs as pure as is reasonable can also do wonders for future multithreading even if slightly slower single-threaded.

I think an understanding of what a modern compiler will and won't do can improve the tradeoff between speed and readability (when present, I think optimization-theatre is quite common amongst low level programmers - based on my own biases)

This is true, even Haskell supports imperative programming and mutation (very well in fact) but languages do need defaults. Given that even OOP thought-leaders argue "favour immutability", I would argue that FP languages offer a better set of defaults out-of-the-box (e.g. persistent collections, libraries for working with immutable data, concise syntax). Mutation is extremely useful and powerful, but if it's the default idiom used absolutely everywhere, then program composition and reuse will be harder to achieve.
>However, looking at how discontent programmers are with Objective-C, not so much anymore. Not even the immaturity of the tooling around the language like its IDE Xcode could stop the migration.

Actually it has little to do with some huge "discontent" towards Objective-C, and more with Apple presenting Swift as the way forward and their main officially supported language...

>So why are most of the young contenders stuck with little recognition in their niches, while Swift is taking off so quickly?

Again, because no functional language has a huge company promoting it as THE language its devs should use, like Swift has with Apple. F# is not MS's favorite, for example...

>For developers building applications in the Apple ecosystem, the primary hard problem seems to be Objective-C. In other words, ”the pain” is so significant that developers were almost desperately waiting for an alternative language and are now happily joining the movement of the Swift language.

Yeah, no...

>The first five of those factors [interlanguage working, possess extensive libraries, be highly portable, have a stable and easy to install implementation, come with debuggers and profilers], which are mainly technical, are provided by almost all of the functional languages.

Not really. Compared to C#, Java, Javascript, it's not even close...

>Following the theory of "The Chasm", FP would need to solve a severe problem that could not be solved with existing approaches in order to make a breakthrough (finding its "killer app")

Not really. Swift doesn't solve any special problem "that could not be solved with existing approaches", C# doesn't, Java doesn't, and in general, most successful languages don't.

They succeed because of platform stronghold (UNIX -> C, MS -> C++, OSX/iOS -> Swift) and other such reasons...

In my opinion, Java succeeded for two reason: the (not quite fulfilled) promise of "write once, run anywhere", and the library. In the beginning, it didn't have "platform stronghold" anywhere, not even on Sun. (Although, if the platform was "everywhere", there weren't many alternatives.) And the language itself was not a spectacular advance. But the library was massive. And the promise of "run everywhere" was very tempting.
FP is fun, but there aren't many good languages for it. Haskell is too academic, Clojure is fun but hasn't taken off, Scala is too complicated (Java with FP shoehorned in, who thought this was a good idea?).

I like FP but 90% of the time you'd be better off with just Python because other developers will be able to work with it and there are libraries. Or Golang or Node or whatever.

Frustrating, but it is what it is.

I find the characterisation of Scala very inaccurate.

It is nothing like Java at all. A Scala code would look so different compared to a Java code.

For an example, in Java you would create a class with static variable as a Singleton object. In Scala, you just create an Object.

Type inference, Option type, pattern matching, it is nothing like Java with FP shoehorned in.

In my bubble Clojure has taken off quite nicely, many companies are solving hard problems with it and you get to enjoy all the libraries of the Java eco-system :)

But it is indeed a very different approach to programming than let's say Python or Node.

> Haskell is too academic

How so?

You know there has been a growing number of professional Haskell developers for the past 5-7 years right?

I don’t see what the big deal is. I wrote clojure professionally for many years, full-time. It’s just as easy to write spaghetti in that language as in something more traditional.
Honestly, I've never seen a language or paradigm that you can't easily write spaghetti in.
Yeah. The trick is, can you write not-spaghetti in it?
Well, I've not seen a language/paradigm that makes in impossible to write good code in, either.

While there are differences, of course, I honestly don't think the choice of language makes the major difference in code quality. What makes the major difference is skill, conscientiousness, and work processes.

> Well, I've not seen a language/paradigm that makes in impossible to write good code in, either.

8-bit BASIC.

FP tends to have a disregard for practicality, and performance especially. Yes, it's elegant, by being abstract, but this abstraction comes at a cost.

After falling in love in it, I wrote a large project in F#, but eventually had to ditch it and rewrite in C#. A simple analysis of any F#-generated IL will reveal this.

Can you tell more about what kind of project this has been, and at what point you decided to turn around?
It was a WPF desktop application, with a parser component. I managed to write large portions of the UI (all in code, no XAML), but when debugging I discovered that the language and the IDE are slowing me down.

Especially, it's very easy to pass the wrong values to functions (functions instead of final values, etc). Debugging this is very time-consuming.

IDE-niceness is also a factor. Devs tend to disregard this, but all the intellisense, code lens, go to, find refs, etc are huge time savers. You lose many of these capabilities (or get them in a degraded manner) with F#.

Yes, I used all the plugins, etc, but what you get is simply 2nd-grade. This is in part unfixable; the language is simply not designed with such aspects in mind.

And, as said, performance played a factor as well.

As someone who has done some dev in F# professionally I think a lot of the comments above could come from trying to use F# like C#. WPF (and in general older .NET Microsoft frameworks) is probably one of the worst cases for F# however; the framework is designed pretty much exclusively for C# usage (i.e. PropertyChangedEventHandlers, generated C# classes from XAML, etc). From a functional language perspective there's different ways of solving the above problems. While you could code WPF in F# it's clunky and doesn't pass the cost/benefit test IMO in its current state; you would be coding in C# style with just a different syntax since the framework enforces a given coding style.

Performance wise I find it depends on what your doing. I've had nicer code run faster in F# than C# with inlining and such. You can resort to mutable coding if you have to in F# as well so I don't think its truly the case. If your using immutable data structures and writing a WPF app on top without understanding them I can see why you would get the performance hit as an example.

I haven't had a problem with Intellisense, IDE niceness (e.g. Rider, VS Code), Go To Refs seem to even work in VS Code etc. All the Resharper goodies aren't there; but after awhile you find you just don't need them as much in a more leaner language.

> Especially, it's very easy to pass the wrong values to functions (functions instead of final values, etc). Debugging this is very time-consuming.

I have the opposite anecdote. I use F# specifically for its strong type system and domain modelling capabilities.

A method signature in C# might look like

public static void HireHandyman(string handymanName, bool sweepFootpaths, bool waterGardens, bool emptyLitterBin, bool mowLawn)

I can do in F# as

HireHandyMan(handymanName:EmployeeName,sweepFootpaths:SweepFootpaths,waterGardens:WaterGardens,emptyLitterBins:EmptyBins,mowLawn:MowLawn)

Each type listed there is a thin wrapper over the bool type, but I can add additional business logic at the type definition and it is enforced throughout the codebase at compile time (for the most part). Is it a contrived example? Somewhat. Does it prevent me from putting the emptyBins argument in the waterGardens slot? Yes, at compile time.

I do concede the lack of first-class tooling (CLI is not enough, mediocre programmers like me like designers and GUIs! shakes cane) is one of the bigger costs to using F# in particular.

(comment deleted)
F# code can certainly be written in C# style (no DU's, use nulls instead of option types, mutables, etc.) and should not differ much from the C# IL. Seems like doing this on the hot-path (or re-write a few fn's in C#) should be enough -- why did you need to ditch re-write the whole project?

EDIT: Just saw your reply. I do agree about the IDE -- having ReSharper, OzCode, etc., on my side is a great advantage on the C# side, even though I'm an F# fan as well.

Also at this point C# is a fine FP programming language itself. (Can 8.0 finally pattern-match tuples sanely?) The only thing missing are DU/sum-types.

unfortunately C# pattern matching is really only a glorified switch with destructuring that doesn't provide any level of exhaustiveness checking that is very helpful in maintaining code under conditions of change.
Agreed. Even w/o DU's/sum-types/case-classes, there could be a compiler option when matching an instance against a lists of sub-classes that a warning/error is generated if the list of sub-classes does not fully cover the parent class. (It should be fairly easy to write a Rosyln-based plug-in that enforces this.) Typescript allows you to express this kind of thing pretty well -- maybe some of that work will end up migrating to C#. F# used to be the C# feature playground, but that's probably changing now. Not sure if TypeProviders will ever make it...
TP's I don't think have quite borne out the usefullness-to-complexity ratio
Agreed, but anything is better than some 3rd-party tool (that may or may not be integrated into the build) doing one-off ad-hoc code generation. I think any C# meta-programming facility would be a good step. Certainly the TP interface(s) could be simplified for C#.
well there are T4 templates for C# code-gen, although I can't say I've ever been eager to use them.
This is my experience as well, although I can't speak for F#. Functional programming languages work, until you hit a performance wall and need to dig a bit lower in the stack. It is when things get ugly that they start to look like fancy calculators.

Besides ATS (which is not very practical), only Common Lisp seems to accommodate to that (and maybe just because Lisp is old and had to deal with performance issues for decades), but it still lacks a state of the art GC.

Compilers care about functional programming in its side-effect-free form because you can only optimize code you can understand the side effects of, and side-effects generally foreclose on optimization. The most obvious example is the volatile keyword in C, and how that forces a lot of memory traffic the compiler would otherwise be able to avoid.
That is the theory.

In practice, the optimizations compilers implement using the advantages of known lack of side effects and mutation generally just aim at recovering part of the performance lost through excess copying.

> Since the early 2000s, functional programming has become more and more popular

This is because pre-2000's, OO was particularly well-suited to desktop software and dominated that space, which also happened to be a space which occupied a large fraction of total development.

OTOH, tasks of data transformation, which after the 2000's became in more demand as software moved more and more from the desktop to the server, is particularly well-suited to FP (due to being on the other side of the expression problem).

The shift from desktops to servers has real consequences on language design.

Microsoft even admitted this as one of the reasons they're trying to bolt on FP features to C#.

I dare say the reason many people are hesitant to adopt Functional programming is that:

A) They aren't, they're probably already programming in a functional programming style. Just not in a purely FP language (Which I would never adopt to begin with)

B) A lot of FP articles come off as the musings of zealots obsessed with monads, which often barely make any sense to, well, anyone. The less sense it makes at first glance, almost guarantees people will want to avoid it. Yes, maybe I can understand it. But I'm (hopefully) not the only maintainer of the codebase, and trying to communicate some FP concepts back & how to use them really, really isn't easy.

> A) They aren't, they're probably already programming in a functional programming style.

This hasn't really been my experience. OOP in particular has a very specific design mindset, and I've seen that play out over several codebases. There isn't really anything I can call "functional" in a system fundamentally based on cyclic (often) graphs of mutable objects.

I think what may be implicit (and hence miscommunicated) in discussions about FP/OOP is that it's not about programming in the small (i.e. specific algorithms, blocks of code), it's about programming in the large (modules and their relationships; management of persistent data). Many examples I see of FP/OOP are algorithmic, and hence uninteresting -- you can get some nice ideas for how to condense your code or express the core ideas better, but it isn't exactly a paradigm shift.

Every Turing-complete language can encode any computable function; algorithms may have complexity distinctions but are ultimately not far removed. The FP/OOP discussion would be better served discussing the architectural implications of these styles.

> B) A lot of FP articles come off as the musings of zealots obsessed with monads, which often barely make any sense to, well, anyone.

Monads are an example of a dominant architectural pattern in FP that takes advantage of the core conceit of the paradigm. I think monads tend to be explained at the algorithmic level, which is unfortunate -- in many ways, they're about decoupling domain logic from control logic, which (I will posit) is desirable in any system, not just one that's FP.

> > To be widely used, a language should support interlanguage working, possess extensive libraries, be highly portable, have a stable and easy to install implementation, come with debuggers and profilers, be accompanied by training courses, and have a good track record on previous projects.

> The first five of those factors, which are mainly technical, are provided by almost all of the functional languages.

That seems like a very generous statement. Unless the author is talking about some functional language I don't know.

Is there an FP language which really has the extensive libraries of Java / Python / C++ / JS ? (You might argue with Clojure and anything with a FFI..)

Is there an FP that has a debugger and profiler as Visual Studio for C++, Eclipse for Java, and your browser for JS ? (No, you REPL does not count as debugger.)

Is there any language that as `interlanguage working` (ok, this one is unfair, only JVM and C really count...)

Is there an FP that has an implementation that's not a nightmare to install ? (ok, this one's even more unfair - everything is a nightmare to install...)

F#
F# should be more popular. But C# is just good enough that the small amount of extra effort of using F# is a speed bump that's hard to get past.
(comment deleted)
The article doesn't mention all the programmers being (forcibly) introduced to functional programming concepts by using React and Redux.

Perhaps this is another possible way to jump the chasm?

Functional programming alone is not very compelling. It's just a slightly different way of organizing your code and data, with different tradeoffs in terms of what code is easy and what code is hard.

If all you do is present examples of using higher-order functions and algebraic data types, people will be pretty justified in saying "this doesn't really change anything important." And that's because it doesn't!

Even in Haskell, once you learn the language, code is code. Sure, laziness means learning new ways to think about composing code, but that's just a small detail. In the end, the things that matter are same. Everything you know about performance optimization still applies. The only difference is the look of the code used to express it.

You replace for loops with higher-order iteration combinators! Woo! It doesn't really change anything. You replace goto with recursion. Big deal! It's all the same thing. (At least in a language with proper tail-call elimination.)

There is no giant breakthrough happening because there really isn't anything to break through... At least as long as all you care about is "functional programming".

There are languages where more interesting things are going on than just functional programming, though. And those have actual promise for providing real benefits. Haskell has a type system that provides real benefits in terms of documentation and correctness. That is actually useful. But it's not "functional programming."

So yeah. I don't care about functional programming. I care about things that are actually improvements.

I don't either consider living without local mutable variables and loops as a clear improvement. But I do think that designing your application such way that it won't rely (or rely as little as possible) on spooky actions at a distance is.
Sure, but that's a best practice in every language. Saying "this language makes you do the thing you swear you're doing anyway" doesn't sound like a practical difference.

The second-order effect of "everyone has to do what you're claiming you do" is meaningful, yes. But it's really hard to convince programmers there's value there. Look how many people still say C is a fine language, you just have to not mess up. And not rely on any library that messes up. It's really tough to market the thing everyone should be doing anyway as a feature, even when the difference between "should do" and "is required to do" is huge in practice.

I like pragmatic definition of FP by Eric Normand: We recognize separation between data, calculations (pure functions) and actions (impure stuff) while using always simplest category.

To me it seems like especially juniors would get benefit from this separations. So is it more like: "this language makes you do the thing that experienced programmers do once a while and juniors avoid [purity] at all costs". It would be interesting to see how juniors would work with functional(-first) language. Would they be able to craft same not-even-god-knows-what-it-does piece of art? What I have seen so far lot of side effects is typically required.

Oh local variables in languages like Forth or Factor are handy. I have not yet gotten used to stack-shuffling. Will I ever? :D
Don't have experience about stack oriented languages nor sure is this relevant reply.

But to clarify: local mutable variables are fine because effect of changing value is clear due well specified scope. Mutation is not observable from outside of a function.

Opposite is true for using mutable data structures (with immutable variables): scope of effect must be checked manually, it's easy to leak function abstraction and with 3rd party code all the bets are off.

How the hell did Kotlin end up on the non functional list, and Scala did?

Kotlin code tends to be at least as functional as Scala is.

If Kotlin isn't functional, then Scala isn't, and if Scala is functional, then Kotlin most certainly is.

You can do functional in Java as well; and people do. It's probably something purists look down on as inferior; and they'd probably be right. However, it does bring advantages relative to non functional Java code and it's been creeping into the language and frameworks for many years now. Kotlin sort of sits in between Scala and Java. Where Scala only grudgingly allows you to do things like for loops and other imperative stuff, Kotlin is a lot less conflicted about this while providing most of what you'd want out of a functional language as well. It supports both styles pretty well.

As a consequence the "my language is more functional than yours" is less relevant these days. If you look at the mainstream languages (Javascript, Java, C#, Rust, Go, Python, Ruby, Kotlin, Scala, Swift, etc.) they all borrow some things from the functional world. They all have some sort of collections supporting things like map, reduce, fold, etc. They all have some notion of lambda functions and passing function references around. Etc. In several of those languages, this has been the case for quite long as well. All of those languages have in common that they are relatively new.

Bucketing languages as functional and non functional is less clear cut than it used to be. In that sense, functional programming has gone mainstream and most programmers are exposed to it now. 25 years ago when I started out, we had some functional programmer pioneers teaching at my university and I got exposed early to what at that time definitely was not very practical in terms of real world applicability. I had my compiler course on parser generator frameworks written in gopher (a haskell predecessor). I even got exposed to monads during that course. You won't see a lot of Kotlin coders talk about monads but when you start talking about side effects, they'll have plenty of solutions nevertheless.

Arguably, Scala is a bit more puristic on this front but the practical value over less puristic languages is not that enormous.

Please don't fancy functional programming in javascript. Its a powerful paradigm and should be used in a language with powerful compiler.
JavaScript compilers are about the most powerful ones out there.
Sorry. I should have shared the example I was thinking of as well.

Just my example.

[lengthy_array].map(function).filter(function).reduce(function).

JS compiler just runs them.

A compiler to be powerful to handle such functional programming syntax should also have ability to inline the functions as a single function.

the above example could be recompiled as

[lengthy_array].array_operation(Three function composed into one)

Oh, forgot to answer here. As a compiler developer I'm very surprised by the assertion that this wouldn't be optimized by something like V8 or GraalVM's JavaScript engine. But I couldn't JavaScript myself out of a paper bag, so I don't know how to verify this myself.
At the end of the day, it comes down to performance. We've been lucky for a long time where the hardware improvements seemed to almost come for free, but the golden age of Moore's law is over, and people finally are realizing that their code needs to be tighter in order to achieve performance. FP doesn't mirror how the actual machine instructions work, whereas imperative languages do. And this means that when you inevitably hit a performance wall, it's generally easier to solve it in an imperative environment because you can already visualize what's going on underneath (save for gc stalls or whatnot). FP has its places to shine, but without the ability to see how the sausage is made (and tweak it), you're always at risk of an unbreachable wall.
FP enables better concurrent/parallel code. I would say that is more important when CPU core count is increasing
> FP doesn't mirror how the actual machine instructions work, whereas imperative languages do.

Can you explain what FP concepts don't "mirror how the actual machine instructions work"? Arithmetic maps to arithmetic instructions. Calls map to calls or jumps, which are well-supported by hardware. If statements map to conditional jumps. Pattern matching maps to something like switch statements (plus extra jumps), which are not hardware features, but they aren't hardware features in imperative languages either. What else? Oh, you don't write "malloc" or "new" to allocate memory (which, again, don't map directly to individual machine instructions). That's about it, I think. What am I missing?

Generators don't mirror the hardware. They are higher order tricks with hidden costs that can bite you if you're not careful. Lazy evaluation is a convenience that is dangerous to think of as free, as is recursion. Code-as-data limits the kind of addressing that can be used in the chip itself. There are mitigations for 95% of cases, of course, and nothing's stopping you from changing the algorithm entirely or parallelizing or whatever. I'm not saying that FP is a dead end. What I'm saying is that it comes with a cost in that you end up limiting your options if you hit a roadblock, because you can't just modify the imperative path due to the higher order functionality you're relying on. FP is very powerful, but that power doesn't come for free. For real-world applictions, a mixed approach will work best for most things.
> Generators don't mirror the hardware.

You mean like this?

    #include <stdio.h>
    #include <stdlib.h>

    struct generator_state {
        int next_value;
        int limit;
    };

    struct generator_state *enum_from_to(int from, int to) {
        struct generator_state *generator = malloc(sizeof *generator);
        generator->next_value = from;
        generator->limit = to;
        return generator;
    }

    int has_next(struct generator_state *state) {
        return state->next_value <= state->limit;
    }

    int next(struct generator_state *state) {
        return state->next_value++;
    }

    int main(void) {
        printf("try to enumerate from 1 to 10\n");
        struct generator_state *generator = enum_from_to(1, 10);
        while (has_next(generator)) {
            printf("%d\n", next(generator));
        }
        return 0;
    }
Oh no! Imperative programming doesn't mirror the hardware!

> Lazy evaluation is a convenience that is dangerous to think of as free

So your problem isn't really FP, it's Haskell?

> as is recursion

It's dangerous to think of any computation as free, so... OK.

> Code-as-data limits the kind of addressing that can be used in the chip itself.

I don't know what you mean here, but "code as data" isn't a universal feature of FP languages. Even in Lisp it's essentially a compile-time abstraction for macro expansion, you don't massage your function definitions at runtime. And once your code is compiled to machine code, what exactly is the problem with using all of the chip's addressing modes?

Maybe by "code as data" you mean "first-class functions", i.e., that you can have pointers to code that you can store in data structures? I'll spare you the C example of function pointers because we've established above that C is a terrible language that doesn't map nicely to the hardware ;-) Maybe it's Pascal you want!