Ask HN: Reasons behind renaissance of functional programming languages
I've been curious about the renaissance of functional programming languages like Scala and Clojure in the software community. Is this a byproduct of our evolving hardware where instead of clock speeds the focus has been on pushing out more cores, so to reap the benefits software developers need better abstractions to make their code easily parallelizable? Is there some erlang-esque promise of pervasive immutability which is vaulting these languages into more popularity? Or is it simply the fact that these newer programming languages have simply learned from other languages' paint points and amplified the good parts by bundling them together neatly? I don't have anything against these languages, I'm just trying to get a deeper understanding of what appears to be a trend in the programming language space.
92 comments
[ 2.8 ms ] story [ 144 ms ] threadI can't truly claim this has driven the adoption of other languages, but Haskell's (or pick some language from the ML roulette) influence on Clojure and Scala is undeniable. Clojure's commitment to immutability pales in comparison to Haskell's, while the latter demonstrates the advantages of such programming in spades. Scala's type system is a novel extension of the HM system which forms the basis of Haskell's.
So am I claiming that the increased availability and "practicality" of Haskell has driven a renaissance in functional programming?
Sort of, yes, but I don't feel it's the core underlying cause. More a symptom in its own right. These ideas are the leading edge of programming language research. They're smart to learn and to integrate into our next generation of tools. This evidence has long resounded from finding them at the center of the "Holy Trinity" of category theory, logic, and type theory. It's "practical" significance is still growing, however.
We just couldn't have practical functional language 20 years ago, in term of both software and hardware. Back then, GC was a rarity, the JVM didn't exist yet. Software has to be ran on the user slow-ass computer, speed was everything and you didn't care much about concurrency/parallel problem. Nowadays, even if the clock speed didn't stagnate and we have just one super core in desktop computer, we would still write a lot more distributed system on the web now than we used to.
Also, we're building more and more complex software over the year. I remember a question for Peter Norvig in "Coders at work", where he was asked about the differences in programming now and back there. In the past, programmers generally had to write (mostly) everything from scratch, and they kept the whole program in their heads. Nowadays, we actually spend most of our time reading other API and trying to plug different components together, referential transparency is simply a godsend.
In a sense, I think the change from imperative programming to functional is similar to the one from GOTO to structure programming. May be we need a "Mutable state considered harmful" to push functional languages mainstream ? :-)
CPU is not really a bottleneck, either, so, you can also spend a few cycles there also.
* Parallelization and concurrency do seem to be easier in functional languages with immutable data. Not easier to write per se, but easier to reason about.
* JavaScript was, as far as I can tell, arguably the first truly mainstream language to embrace first-class functions and closures. The ubiquity of JavaScript has exposed many to the benefits of such an approach. Similarly, Rails and other Ruby-based software make lots of use of functional programming through Ruby's do-blocks. These languages have made people more comfortable with first-class functions.
* Languages like Haskell, Scala and Clojure have shown that functional programming can be high-performance and one need not necessarily trade speed for expressiveness. Similarly, many scripting languages (and/or the hardware they run on) have become fast enough to allow for them to be used for high-performance applications.
* Functional programming is fun, and allows for beautiful and succinct code.
This is a nitpick, but Perl has had closures since the early 90s -- before Perl5 even.
2. what is the crossover of internet-capable devices also running Java or C? like 100%?
3. you are only defending your assumption that there is a bigger install base, not a bigger developer base.
The problem with the TIOBE index is that it also seems to factor in courses and services--I wonder if there is a straight-up developer census.
That'd solve the question rather thoroughly. :)
embedded systems + financial/government sectors + academia + video games + mobile apps (compared to simply "web development") is my defense against the notion that there are more Javascript developers.
Still, as far as I know, the work horses in some of the biggest firms in the industry are those not-so-FP languages, like Java, C++ and Python.
FP is very cool, but I think it has yet reached that far to be treated more seriously like those more mature ones, which represent not only the language itself, but also the ecosystem behind: tools, libraries and community.
10 years ago I would see the very occasional article about Lisp. Now FP discussion is everywhere. Whether it's being used in prod systems or not, FP is certainly gaining attention.
Hopeful answer: FP languages have gotten enough better than the current mainstream that they can't be ignored.
I believe it is a bit of the Hopeful answer but mostly the Cynical answer. If you compare java and Clojure(or Scala for that matter) on the programming language shoot out Clojure is neither more concise nor faster than Java. So why all the hype then? As far as I can tell it is book sells and the fashion cycle.
But that said, high performance java is both slower and less concise than C by the same metrics. So if you think this is just fashion, then nearly every language outside of C is also just fashion.
In my view, languages as a whole have been moving more and more towards the functional space over time. Newer languages, or versions of existing languages, typically have more functional features. Languages are trending towards higher order. As a result of this, the existing higher order languages, the functional languages, are suddenly much closer to mainstream and so have become more popular as the majority become aware of their benefits.
Clojure's syntax isn't optimal for low-level in-place mutability, but macros can go some way to resolving that. The few times I've worked on high-performance Clojure code, it hasn't been too difficult to get performance comparable to an equivalent Java library.
Java is somewhat slower than C, but it's generally within an order of magnitude if you stick to primitives.
I like Haskell. I like it in theory and I like playing around with it. I like the discipline it requires having to re-think "everyday" things in order to solve them in a new paradigm. I started with Python and then learned half a dozen other imperative languages so Haskell is utterly alien to me apart from the most basic concepts like recursion. I liken it somewhat to learning Vim -- you make the simple complicated and gain something in the process. Haskell is the number one language I wish I was working in at any given time.
So why am I not using Haskell? Most of my time is spent on OS X and iOS. While I could shoehorn Haskell into a project it doesn't make business sense to do so. I couldn't justify the extra time, complexity and I certainly couldn't justify it to a client. There simply is no good answer to "what about the next developer?" and other related questions. (I think this is why shoehorning a paradigm into an existing language is much better approach when you have a tight coupling of language and platform -- I'm thinking of RAC here.)
Give me something to work on where Haskell is the obvious choice and I'd be all over it. Until then it has to stay in the toy box.
To some people, unfamiliar technology is scary, possibly unacceptable, and often far from 'obvious'.
I don't like the metaphor or idea behind "you make the simple complicated". I prefer to say this: with functional languages, you name more things: mapping, folding, and so on, because you use them so often. Then you get comfortable thinking in higher-level ways. This means you can build on them more effectively.
I don't speak for him, but I don't because I don't want to do wrong by my customers. I don't do long-term support. I can maintain a heavily FP application (in Haskell or whatever else). Most programmers can't.
That it has its advantages is good for me. Those advantages make it even harder for normal people to get good development help.
When I say simple things I mean what's obvious for someone who programs primarily in imperative languages, like top-down, line by line execution in functions or local variables in functions. If you can take the same functions and understand them as operations on lists of things then both ways of looking at the problem are valid, though the latter won't be obvious without having the relevant experience.
> But when you see a possible fit for Haskell (I would hesitate to make 'obvious' be the bar), have you tried to persuade or demonstrate the advantages?
I have yet to. Again, I work primarily with Obj-C. Integrating Haskell would mean complicating a fairly elegant collection of tools and libraries. "Hey I like FP" isn't something I'm willing to sell to clients nor do I think it's the responsible thing to do. I go to great lengths to ensure that I'm delivering a product that could be understood by and maintained by developers with a wide range of experience / skill. Integrating a second language / paradigm into that without any clear gain would be counter to that.
> Why not find customers/areas that would be open to using Haskell?
For me it's really a chicken and egg thing. It's not easy for me to bring Haskell into my professional or even personal projects so I'm not experienced enough to go after primarily Haskell projects. What would make me consider it would be significant downtime caused by a lack of projects in the language(s) I'm already familiar with. Until that happens I'm not sure I'll make the jump.
I could possibly see writing libraries in Haskell but again it's hard for me to make that jump when I know I could write it faster in C/Obj-C because of my familiarity. What I like about Haskell (the type system, how succinct it is, functional purity) I can get most of the benefits of in Obj-C. I rarely if ever use dynamic types and I tend to write Obj-C (well, more and more these days) in a functional style by leveraging the relatively new addition of blocks.
This makes me angry at "ordinary" programmers. They think it's obvious, but they never rigorously modelled the sequential execution in the first place. Instead, they use their instinct. Instinct is efficient, but when it's wrong, tough luck.
This is probably why proving the correctness of a program is so difficult: you have to pin everything down mathematically, including sequences of side effects. For most people, that's much more difficult than merely relying on their guts. As a result, no one proves their programs. Maybe they test them.
With Haskell, you can't even program without pinning it all down mathematically. As a result, no one uses Haskell… OK, not no one, but still that's a significant barrier to entry.
I wish programmers were more mathematically aware. I wish they realised they're doing applied math, whether they like "math" or not. I'm tempted to blame our education, but I'm not sure it's the only culprit.
The best advice I can give is, don't be content with words and labels. Search for the underlying structure. Take monads for instance. Lots of tutorials, lots of examples. But I didn't really got them until I read the Typeclassopedia: when you get to read the word "monad" you realize it was explaining the monadic structure in depth from the very start.
Practice also helps. Implementing a Parsec clone in Ocaml helped me understand applicative functors and monads. (I also experienced some of the disadvantages of strict evaluation.) You may want to try that in Clojure.
Finally, when something seems impenetrably abstract or obscure, that may be because you lack some basic vocabulary. For instance, you can't understand a paper on type inference if you don't know how to read type rules: https://en.wikipedia.org/wiki/Type_rules Which you can't read if you don't know what's an environment… As I said, it takes time.
Pendulum now swinging back the other way. Functional, data structure oriented programming has many benefits above old-school procedural programming e.g. C, Fortran. But it also doesn't have the baggage of mainstream OO languages. Thus, this feels like an appealing -- and new -- ecosystems.
This -- along with a rediscovery of some functional concepts that seem have more importance in a distributed setting, like immutable data, purity, higher-order functions -- have led to some renewed interest.
I predict that there will eventually be a FP backlash that reverses the situation again (hey, look how easy objects are to use vs. this crazy FP stuff!?).
But that's besides the point. I'd like to find out what gaps can be filled so you no longer find FP difficult to understand or use. What material have you tried so far?
The Scala community eventually drifted away from OO, but it could have gone very differently.
A pure function has a very portable interface that makes it suitable for the distributed and social nature of the way we create software together.
These kinds of problems were not envisioned by the creators of the original Object Oriented systems like Smalltalk. Objects were designed for personal computers and building and using software designed for personal computers.
While shared workspace environments were explored in systems like Self, they were always designed around the objects being these visual instances running in a GUI.
Objects detached from a system like Self or Smalltalk lose a lot of their powers of abstraction. They are not and have never been portable, even if they were designed to be reusable.
Citation needed. I personally don't talk to other programmers in terms of functions, but I use plenty of metaphors and analogies that come with my evolutionary capabilities to use natural language (math, on the other hand, was something I had to learn).
Programmers talk to other programmers in terms of functions all the time. Every API you use exposes functionality. If that API assumes some sort of state, that can cause issues for the consumer of the API. It also forces whatever entity is maintaining state be tightly coupled to the consumer and leads to centralized systems.
If the API does NOT have state and instead uses a token based system for authentication and access permissions it is operating in a functional manner. State is maintained outside of the function.
The less coupled that two modules are the more portable that they are. You can bundle up something like the "express" npm package and ship that off to whomever. You can easily build modules on top of an express application by passing the entire app to another module. This pattern has been used to build an entire ecosystem of loosely coupled middleware.
These are not Object Oriented designs. They aren't entities that communicate by sending messages to one another while floating around in some global workspace. They are interfaces that pass state around as arguments to function calls.
Global state is very nicely demonstrated in how modules can be shared between Node and Browser Javascript. What is global? All of the I/O. Files, XHR, mouse clicks, sockets... all of these are the inputs and outputs and all are handled by "window" or "process" or other global state.
Modules can be easily be reused between the server and client if they do not interface at all with any sort of global state.
I seriously doubt it. In order to talk in terms of only functions, you would need to give up identity...because what is identity but not a key for encapsulated state? Without identity, you really are talking with just values, but you have problems describing things with handles. There is no single Bob, just a new Bob who is reconstituted each time you talk about him. Naming anything is weird, and the pure lambda calculus of course avoids it. Most APIs are not purely functional, but somewhat object-oriented (oriented around identity) if only in a few key aspects that are needed to do anything at all.
If you didn't have an identity, then that would be impossible, it is like a superpower where no one could "remember" who you are, and therefore nothing about you.
A UUID is synonymous to state, and in fact, procuring and propagating these IDs would be the main step to implementing state in a pure language.
I'm also not certain why you think this conflicts with the idea of talking "in terms of functions".
Take Facebook OAuth for example. A user logs in, is provided with a signed access token by FB, and then uses that token to prove to an application that the owner of the secret key has granted them permission. The owner in this case was Facebook itself.
This can be verified by the server by comparing the:
var expectedSignature = crypto.createHmac('sha256', FACEBOOK_OAUTH_CLIENT_SECRET).update(encodedData[1]).digest('base64').replace(/\+/g,'-').replace(/\//g,'_').replace('=','');
with the signed request signature:
var signature = signedRequest.split('.',2)[0];
and making sure that they're the same.
This way the server never needs to maintain sessions, cookies, or a whole bunch of other crappy, centralized, coupled, insecure methods for building networked software. The server only needs the secret keys of whatever access tokens users might be providing. The access token contains the userId or any other relevant information. If the server needs more information about the user, it can provide the access token to another API that returns more information about the user, again, based solely on the access token, just by passing state INTO whatever system/function/service needs it.
If this server is sitting in front of a database all that the server cares about is what the access permissions are of whatever incoming request it is dealing with. It still doesn't need to maintain state. The database is maintaining state, but the server is just verifying that the request can make the changes to the state of the database.
All with the wonders of functions, modules, and APIs that try to operate without managing their own internal state, which again, is the main feature of functional programming languages.
I've been coding a bunch of Rust lately, and I'm happy to discover it has my favourite thing from Haskell: the "if it compiles it's usually correct" feeling is wonderful. My software feels rock solid to me, even while it's being heavily changed.
It almost certainly translates into more reliable software, but even just the feeling is enough to hook me.
1. change a core type or function 2. fix all the type errors 3. yay
This is wonderful. I think the tradeoff is that you start a new system, you have to delay running the code for a while. Until you have your core. (Fortunately there is undefined :: a for such uses.)
Limitations of hardware mean we're increasingly looking at computing in parallel, which is a natural fit for languages that emphasise immutability. Distributed computation also benefits hugely from immutable values, as it sidesteps much of the problem with cache expiry.
We're also seeing a demand for more reliable systems. Taking mutability out of the equation eliminates a significant area of possible bugs, and allows for more sophisticated type-checking.
The third reason is simply that it's only recently that we've gotten good functional languages with a comprehensive and mature set of libraries. Haskell has been around for decades, but when I first started learning it seven or eight years ago, the set of libraries on offer was very thin compared to Haskell today. Scala only popped onto the scene 11 years ago, and Clojure only 7 years ago.
* Performance is not that big an issue for many applications. And if performance is not an issue, then neither is parallelism: the only reason to do parallelism is for performance (as opposed to concurrency, which makes sense even on sequential processors). So parallelism only really matters for performance-critical applications, because in most non-performance critical applications, you can squeeze out 10x by just running a profiler and writing better serial code.
* If you do want performance, parallelism alone is not sufficient. On modern processors, data movement is significantly more expensive than computation. And in that regard, most functional languages perform poorly. Imperative languages, for all their faults, give you much more fine grained control over memory usage patterns. So for performance-critical applications (which are again, the only applications where you really care about parallelism), it is not uncommon to see the core of the application written in C/C++, even if the rest of the application is written in something else.
By the way, if you aren't measuring your performance by comparing it against the peak compute/memory bandwidth of the machine, then you don't really care about performance, because you don't really have any idea what you're leaving on the table. This is why it's possible, for many applications, to give the code to an experienced performance programmer and see speedups in excess of 10x.
And I'm sorry but when you and even rich says it it's misleading conflation intended to confuse the listener.
Implementing stateless systems in OOP is trivial. As in fucking a child can do it. And we have been doing it for DECADES.
This "reasoning about" meme also implies that all code we write is inherently algorithmic and simply a computation.
It is NOT.. 90 percent of code is just moving data around.
The ten percent of algorithmic code, That involves actual math is usually trivially implemented in OOP languages.
So lets rid ourselves of blowhard statements like "reasoning about'
Because if you had any real experience you would understand we deal with these problems quite simply in OOP every day.
Here's something for YOU to reason about. Us OOP guys can do the same thing better and actually understand the code 2 weeks later. We don't need to "reason" about it
Design for performance thus often comes at the cost of development agility and operational correctness. Being correct and agile yet still meeting performance criteria is a bigger win for most businesses, which usually aren't constrained by cost and raw speed of hardware. Functional programming, to the degree that it let's you exploit machine parallelism, gives you more leeway for good design before you risk missing your perf requirements.
And that's a reason functional programming is actually given a boost by hardware parallelism.
(Much bigger is that it's often a better way to structure programs, and now there is less integration costs since you hide behind the - yes - functional, stateless API of a http request handler, an explicit function of input to output.)
PS: your perspective on perf is kinda off to me. Almost all applications care about performance. If they never terminated they'd be useless. Performance isn't just a priority, it's a requirement. But usually it's just a deadline and a hardware cost multiplier - and money saved on hardware may not be enough to pay for extra / more expensive people elsewhere.
This point illustrates exactly the reason why people don't really care about performance. Performance is an arbitrarily deep rabbit hole that you can go down as far as you want. But because performance trades off with other things that people frequently want more (simplicity and maintainability, among others), they stop when performance is "good enough". What is "good enough" for most people? Probably 10x away from what the machine is actually capable of.
You probably think I'm being flippant by claiming that these sort of speedups are possible on real applications. I am not. In high performance computing (HPC), this happens surprisingly frequently, perhaps because people are willing to trade off almost anything for performance. Here's an example of a paper showing speedups over some 30 year-old Fortran/MPI code:
http://conferences.computer.org/sc/2012/papers/1000a040.pdf
And for this particular application I happen to know that there is another paper in submission which shows additional speedups over what this paper got. People who are willing to squeeze keep finding ways to optimize this application.
This is so true, and is really an emperor-has-no-clothes statement with respect to this claim that in the future we're all going to use immutable data structures to leverage multiple cores. Every situation where I've had to write performant code has ended up in one of these two cases:
1. All the time is spent in linear algebra, in which case it's all about planning out the computation so LAPACK can do its thing.
2. There's some funky custom signal manipulation. Some tiny bit of code needs to be in C, with everything in nice packed arrays in the right order so you can sweep straight through.
It would be great if there was a 10GHz CPU (single-core), for some special domains.
A hardware startup company that designs a new CPU that interrups the status-quo would be great. (3GHz in 2004, 3.8GHz in 2006, ~4GHz in 2014)
Like in the 1990s 3dfx (GPU) and Cyrix (CPU):
http://en.wikipedia.org/wiki/3dfx
http://en.wikipedia.org/wiki/Cyrix
There's a reason it hasn't happened.
In 2014 we have now the Intel Haswell (14 nm) with 3D tri-gate transistors yet just 3.7 GHz single-core clock rate.
A 10 GHz CPU from Intel would be possible today, we just need dielectric liquid cooling (not water, but pressured Fluorinert) like the http://en.wikipedia.org/wiki/Cray_2 and http://en.wikipedia.org/wiki/Fluorinert
General public cannot buy such equipment, but it does exist.
But yes, the speed of light limitation on signal propagation is a major factor in our current limit of 3 to 4 GHz chips.
- size: higher frequency means you need smaller circuits, otherwise the electric impedance works against fast switching. There's a limit to how small we can build chip components right now.
- molecular stability: higher frequency requires higher voltage (to provide the energy), which in turns makes it easier for the metal oxide to degrade over time (this effect is additional to degradation due to heat)
- phase divergence: the digital circuits in our processors are heavily synchronized, and require components to react simultaneously to clock edges. However the propagation of the clock signal across the chip introduces errors in the signal phase. As the frequency increases, phase errors accumulate and cause circuits to "lose synchronization". To avoid this, one must increase the complexity of the clock distribution network greatly, which in turn compounds the effects above (and the heat problem).
All in all the current state of affairs is summarized by a rule of thumb (so-called "Pollack's law"): the speed (instructions/sec) of a single core processor increases with the square root of its complexity.
By this rule, to clock up from 3 to 10GHz would be a 9-fold increase in complexity, for which we don't have the technology ready just yet.
As processor architects are hitting fundamental physical limits when it comes to increasing clock speeds[1], it would probably take a team of world-class engineers, not a few disruption-minded startup founders, to create a 10GHz CPU. Such a chip would have extreme cooling and power demands and wouldn't necessarily perform well.
Cyrix doesn't seem like a great example, as it mostly competed with Intel on its budget chips, if Wikipedia is correct. I suspect the greater amount of low-hanging fruit in processor design made it easier for smaller companies to compete with Intel in the 90s.
[0]: http://arstechnica.com/gadgets/2011/04/ask-ars-whats-the-rel...
[1]: https://www.quora.com/Why-havent-CPU-clock-speeds-increased-....
http://www.reddit.com/r/askscience/comments/ngv50/why_have_c....
We had already complex pipelining superscalar architecture with Pentium Pro and Pentium 4 (Netburst/Prescott). The current Core Architecture has a lot simpler pipelining based on Pentium 3/M. (see http://en.wikipedia.org/wiki/Clock_rate )
I favor a high single-core over a slow many-core CPUs.
Have you ever coded a many-core application that runs on thousands of CPUs? I have done using it using http://en.wikipedia.org/wiki/Cilk , http://en.wikipedia.org/wiki/OpenMP (and CUDA and OpenCL on GPU), as well as traditional using operating system process and threads.
You need new algorithms that work on massive parallel computers. Converting algorithms from serial to massive parallel is possible in many cases, but really hard science work (have done it).
Nevertheless, for a specific domain I would need a really high speed single-core CPU.
A good book about the topic is "Inside the Machine" from ArsTechnica: http://www.amazon.com/Inside-Machine-Introduction-Microproce... ...and various university lectures.
But originally, you said 10 GHz, a record-breaking clock speed, would be advantageous. I replied to say that I doubt that, given the physical limits mentioned in the links I shared above. If what you originally meant was that processors with fewer cores and better raw performance per core is what you need, then I misunderstood.
>Have you ever coded a many-core application that runs on thousands of CPUs?
Nope. I admit you have more experience in that area than I do, but I don't really see why you brought it up.
>Nevertheless, for a specific domain I would need a really high speed single-core CPU.
Out of curiosity, which domain do you have in mind?
Ivan Sutherland has done some work on a new processor architecture called Fleet, which takes this premise and rethinks how we should program from the bottom-up. Instead of instructions performing operations, the programming model becomes one of passing messages between individual units in the processor, and the problems become that of traffic management and routing, which happens to relate to functional programming, the actor model, and data-flow paradigms.
Have a read of "The tyranny of the clock", and other publications by the Asynchronous Research Center:
http://web.cecs.pdx.edu/~mroncken/ARC-2012-is13_TuringCenten...
http://arc.cecs.pdx.edu/publications
20 years ago you needed to write desktops apps, so you were limited to C/C++. Then 15 years ago you needed access to java libraries, and the only real JVM language was Java.
Now, you just need to build a service that speaks HTTP, so you just need a HTTP server, a HTTP client library, and a database adapter. That means you can build your product in any language you like, and not lack the ability to succeed.
CircleCI is written in Clojure. We communicate with all our vendors over simple REST APIs - it only took a few minutes to write our own client bindings for Stripe and Intercom.
Contrast this with the 90s were we needed to write user interfaces where state was the point, or C++ gamedev.
I'm not taking a stand here, just posing a possible alternative explanation. At least, I've thought about the OP's question and guessed it was a false generalization of my own progress. Data in (dis)favor of either.
Is there an actual increase in FP language adoption? Probably there is, within the population that reads HN. Within the programming world at large? I have no data, but from seeing some places that claim to measure usage, my perception is that any increase in FP in general usage is fairly small.
Reason 1: Object Oriented Programming becomes less popular. After the 90s people started to see that OOP is not really the solution that scales to unlimited complexity. It was a step forward but nothing more. Many different things got tried, like Aspect Oriented Programming, but none of that really stuck.
Reason 2: The moment we had processors with more than one core we suddenly had a need for general purpose parallel processing. While the solution to this now seems to be using tools/frameworks like ZeroMQ, another reasonable option were languages with different paradigms, like functional.
I think that both these things happened nearly at the same time got a lot of traction to functional languages. I am following this since 2008, though. That functional languages still didn't make it to the top of popularity currently results in me no longer believing that they will ever be. Functional languages always had this kind of swingy popularity where a small group of people where strong hearted followers while the general opinion always swings between "this is ridiculous" and "maybe we could use it for that use case".
All in all I would say, the question is a great one, now that the current renaissance of Functional programming is pretty much over.
1) Complexity: Managing complexity is just easier with compact syntax, immutability etc. Applications are becoming larger and more complex, and languages that help reducing coupling and code size will become more popular than those that easily allow getting the job done at the expense of high complexity (e.g. OO/imperative).
2) Concurrency: With concurrent/multi-threaded applications being par for the course rather than something exotic, functional thinking is now required for many applications regardless of language.
3) Modularity/Decoupling/Interoperability: SOA and API's means you can develop independent bits of software that communicate in some language agnostic way (e.g. http). The CLR and JVM now both have support for functional languages that work well with their imperative siblings. This means you don't even have to be loosely coupled by http, you can write an application where the logical/computational bits are F# and the UI is C# while in the same application.
Apart from these we must not forget that almost all the large imperative languages (C++/C#/Java) have gained numerous functional constructs in recent years. Few of us can imagine working in an imperative language without lambdas these days.
So functional thinking has slowly been sneaking into the imperative programmers day job too. This has made more of us interested in these languages that consist almost only of these bits we find to be the most elegant in our OO languages. It's simply less scary. In 1998 the difference between Haskell and Java 1.1 was quite large. In 2014 the difference between C#5 and F#3.1, or between Java 8 and one of the functional JVM languages, is no longer big enough to make it scary.
It's just a subculture that couldn't gain critical mass without the internet. Like furries it has a wide but sparse appeal.
It is a subculture that's not simple though, it takes a while to get into, unlike being a furry you really need to do it in your job to be good at it hence it's only starting to hit it's peak.