It's somewhat funny that this article seems to miss the very practical rise of functional programming style in JavaScript, especially with the rise of libraries like underscore.js
Of course JavaScript has some pretty severe limitations as far as functional programming goes, the biggest being really cumbersome lambdas, and a lack of implicit return. If you try to program in a functional style in JavaScript you'll be fighting the language more than you'd like. However both of these issues are remedied in CoffeeScript.
As someone who was a lisper before getting into web development I'm really surprised to see lambdas, closures, pattern matching/de-structuring bind, let statement equivalents and more be part of a language that is not even talked about too much as being lisp-like or functional. Also important is that CoffeeScript's main selling point is that it's practical and more sane then JavaScript, not that it's functional or lisp-like. At the same time CoffeeScript is probably the closest thing I've seen to a (potentially) successful lisp-without-parens
Functional languages will gain serious traction, but I think it will be when their users find their features convenient and helpful (coffeeScript) rather than interesting/mind-blowing/etc (scala, haskell, erlang..)
> Also important is that CoffeeScript's main selling point is that it's practical and more sane then JavaScript, not that it's functional or lisp-like. At the same time CoffeeScript is probably the closest thing I've seen to a (potentially) successful lisp-without-parens
Have you tried Lua? It has full lexical scoping like Scheme (so you don't have to (function(){})() all over your code to create closures) and has saner built in types than vanilla JS, while also being much faster (around SBCL\Java speed with LuaJIT).
I'm writing a basic functional library for it here if you need some stuff like map, foldl, foldr, partial, filter to get started: https://github.com/davidhollander/fn
Unfortunately, Lua has statement- rather than expression-oriented semantics (i.e., no "implicit returns"). It's quite nice otherwise, though, and its integration with C is hard to beat.
> Unfortunately, Lua has statement- rather than expression-oriented semantics (i.e., no "implicit returns").
This is largely irrelevant for anything related to developing asynchronous services such as web or servers. Asynchronous web development using callbacks is a form of continuation passing style, where control is often explicitly passed using a callback. Since you are explicitly passing control, you usually never have to return values anyway. The 'return' keyword just becomes a bonus feature for convenient error handling.
Having a language with good closure support just works phenomenally well for asynchronous web development. For instance, sending an entire message asynchronously can be a pain because it can fail at any point in the message and require restarting at that point and keeping track of when it has finished.
It's a piece of cake in Lua though, due to its excellent support for closures:
-- SendAll
-- Start sending a message on connection [c]
-- Close when done.
function SendAll(c, msg)
local n=0
OnWrite(c, function(c)
n=n + c.fd:send(msg, n)
if n>=#msg then
c.fd:close()
return 'close' -- just for kicks
end
end)
end
The variable "n" is a counter for the number of bytes sent to the file descriptor "fd". The write callback lambda assigned with OnWrite can always access the appropriate counter "n" based on its creation location. No extra work was needed to create the closure, unlike in languages such as JavaScript.
In Lua, unlike in JavaScript, you don't need to use closures for async programming most of the time.
-- SendAll
-- Start sending a message on connection [c]
-- Close when done.
function SendAll(c, msg)
local n=0
while n<#msg do
yield()
n=n + c.fd:send(msg, n)
end
c.fd:close()
yield('close') -- just for kicks
end
Coroutines aren't as flexible as continuation passing style and add significant overhead for the non-vital syntactic sugar they give you.
I'd much rather explicitly set an OnWrite event that has a one-to-one correspondence to a socket write event from a poll() system call, than create a ton of coroutines and juggle "resumes". This is especially true if you have a usecase where you want to start sending while you are still reading, this would require the creation of 2 coroutines per each context.
While Lua coroutines are significantly better than Python generators by having a more functional than syntactical "yield", I still feel it does more harm than good for structuring asynchronous applications.
Coroutines are less expressive than manually doing CPS, true, but they do make many common cases simpler. They're ultimately as expressive as one-shot continuations.
I never said it did. Of the many complains in-thread about Javascript, it's the main one that also applies to Lua. I'd say Lua's coroutines are a bigger feature for asynch. development, though.
I wrote an embedded non-blocking / event-loop webserver in Lua as part of one of my projects (a distributed filesystem). I got sidetracked by other projects, and lost interest in writing non-blocking webservers after I got into Erlang, but plan on getting back to the filesystem soon. If I find time to neaten up that code, are you interested in swapping notes?
One tricky part is error handling - I spent a lot of time on that (and was pretty impressed by Erlang's error handling model). I don't know how well node.js does that, beyond managing control flow by hand.
It works for HTTP but has few features so far. I have a bunch of exploratory code lying around though, so I could be adding message passing or better fileserving to it in the future. I will send you an email at some point.
I think I'm currently in the "I just don't get it camp" when a significant deficit of a language is the lack of implicit returns. Is typing return that bad? I quite like the readability. Is it that you can only return once per function? I already do that, but recognize that some developers don't. If that's part of it then a lot about these languages is to keep the riff-raff out? If that's true then I think we can probably all agree they will never be mainstream since in most cases mainstream == rif-raff.
It's not about readability or "keeping the riff-raff out". Needing to type "return" itself is a minor detail, but explicit returns are a strong sign of having statement-oriented semantics, rather than expression-oriented semantics.
In languages based around statements, things are done for their side-effects. Returning a value is itself a kind of side-effect, hence an explicit return statement.
In languages based around expressions (Lisp, ML & Haskell, APL, etc.), the language itself gently encourages side-effect-free programming. In Scheme, for example, you usually use a begin block when you need to do things for their side-effects. While it doesn't prevent side-effects entirely, it does make them stand out, and adds a subtle pressure against their overuse.
I don't think I'm quite there yet. Are you saying having to type return vs. it being implicit encourages side-effects in programming? How does this relate to the begin block?
Mostly, yes. "return" isn't the cause, though. Just a sign that the language's primary concern is the side-effect of running statements, not their values (in which case, having a result value would be expected, not a special case). A sign of different priorities in the language design: functional-by-default or imperative-by-default.
The begin block is how one indicates "do this, ignore its value (just do it for its side-effect), then do that and return its value" in Scheme. Some forms have implicit begins, however.
I may just be repeating myself, but I hope phrasing it slightly differently helped. What made it clear to me was learning Scheme and (especially) OCaml, then going back to Python and programming in a functional/expression-oriented style, seeing the subtle ways in which the design of the language resists it. Lua is more friendly to functional programming than Python (it has tail-call optimization, for starters), but those explicit returns still show it isn't a perfect fit.
One reason for not having return, has to do with symmetry, which Scala is full of.
For example, val x = if(foo) { a } else { b }
This is a lot nicer than the alternatives, and I suppose you could force people to write:
val x = if (foo) { return a } else { return b }
...why, why? It doesn't really add much. Once you get into the functional mindset, it becomes natural how this works, and the occasional place where you are forced to add a return statement becomes a place where there is almost certainly code smell. No returns is basically one of those constraints that helps guide you towards more functional code with fewer side effects.
I know this is 10 days late, but the big factor is not whether you type 'return', it's knowing that everybody else has. When you have implicit returns you can always know that a call to a function will return a value, this is essential to proper functional programming technique.
It's because it makes it harder to prove that a function does one of only two things: returns a known type, or throws and exception. In Python it's legal to have a function that can return 0 or return "hello" or nothing at all.
His arguments about the existing functional languages can be roughly split into two categories:
1.) Languages refuse to make compromises and therefore are obscure (Haskell, Erlang)
2.) Languages are crippled by making too many compromises (F#, Scala).
He presents good arguments about why both types of languages can't currently break into the mainstream, but it unfortunately seems like these options form a partition of the possibilities (i.e. a functional language must fall into one of the two). If this assumption is correct, then by his analysis no functional language can break into the mainstream.
I'd love to see a discussion over whether or not that assumption is valid, but for now let's assume it's true. I don't think the languages are the problem. Instead, I think it's the general momentum and consensus of the community. Without books like Learn You a Haskell (http://learnyouahaskell.com/), Haskell would be an order of magnitude more difficult to begin learning. I'm still trying to figure it out, and there are a lot of examples of topics where a similarly good tutorial would ease my learning. Eventually, as the language gains popularity, more and more such work will exist. Furthermore, if popular companies demonstrates that it's a great choice, more people will want to pick it up. If all this stuff happens, our intuitions will grow and adapt to make such a language a natural choice. In summary, the future of functional languages depends more on our understanding and promoting them as a community, as opposed to the languages themselves.
You make an excellent point about the primacy of the community. I can't remember where I first came across the idea that languages are communities, possibly Richard Gabriel's Patterns of Software.
As someone about to embark on the Standard ML learning curve (motivated primarily by Ur/Web - Ur is a ML-like language), it is striking that the SML community is fragmented to the point of non-existence (not even a Planet SML, the sml-list is dead, & the SML subreddit is pretty lifeless).
Looking at Alice ML which has significant advancements over both Objective and Standard ML, it has great features, but no momentum which isn't helped by the fact that there hasn't been a release since 2007.
I learned a lot of SML in college, and it is really a great language. In my opinion it has the best syntax and REPL of any language I've used.
But Haskell has a much better chance of becoming main stream. The type classes allow things like drop-in, easy-to-use hash maps and a simple, type-safe print statement (SML's requires explicit string conversions). Furthermore, GHC consistently pushes modern features; my current favorites are the extremely performant userspace threads (managed by epoll). From what I can tell, the SML folks are more focused on PL research projects than trying to implement a standard library, which is completely fine.
If everything goes well and we as a community build intuitions for strong, static typing, one of these good languages (IMO probably Haskell) could end up as the next Python.
BTW, if you're looking for resources on learning SML, I'd look at Bob Harper's books (http://www.cs.cmu.edu/~rwh/)
This is a refreshingly honest analysis from someone that has a lot of skin in the game. I completely agree on both points. First, the functional paradigm is important and a step forward for most problem domains. Second, none of the current crop of functional languages is going to truly break into the mainstream.
I think it's more likely that we'll see more and more functional techniques trickle down into mainstream languages than it is that we'll see a pure functional language adopted as-is. C++ just picked up lambdas, after all. I do regret somewhat my dalliance with FP over the last decade though. If I'd invested that time in mastering DSP or graphics programming instead I'd be better off overall.
There is a definite functional trickledown effect going on with mainstream languages.
I have the suspicion that the breakthrough functional language will be like CoffeeScript in that it compiles down to Javascript taking advantage of the high performance Javascript runtimes and the functional core of Javascript.
Nemerle's been around for years and I don't see it getting any traction, especially in the shadows of both C# which has been cherry picking functional features & F# which has the backing of Microsoft.
The author claims, in the title, that functional languages will rule, some day.
Then he does a tour describing each would-be-ruler functional language (erlang, haskell, ocaml, F#, scala) and explicitly says that all of them will remain niche languages i.e. will not rule.
His thesis is that none of the current crop of functional languages will rule, but that some new functional language not yet invented (or widely known) will.
A language can't come out of nowhere, because it won't have the critical mass of people, libraries, etc to be usable for "real work". IF a functional language is going to be mainstream in only 5 years, then there are a significant number of people using it today, and it will be generally known in the FP community.
Even F# was a) in beta for years b) solved the library problem by piggybacking on C# and c) had a critical mass of OCaml users who could jump straight into it.
All the machinery of functional programming languages that's creeping into non-FP languages is great. I actually think that FP one-liners are usually _more_ transparent than the corresponding non-FP loop.
However if I'm not mistaken an important point of FPLs was to eliminate side-effects and that the ultimate goal was program verification (not validation). I.e. you could prove a program correct in the mathematical sense. That seems still a long way off.
The trend I'm seeing isn't towards verification by proof but leveraging the type system to ensure that the compiled program is correct and secure. Both Opa and Ur/Web take this line.
Kind of my point. I think he's meh on Ocaml because Scala has the same features & runs on the JVM, seeing it after using Scala wouldn't be very exciting. However Ocaml was around years before Scala.
It's an interesting analogy. Whenever Karate fighters enter MMA contests, they get their arses handed to them by BJJ fighters - the beauty of their art doesn't translate into effectiveness in competition.
Yes it does. It's hard to be a successful MMA fighter relying on just one martial art. Just look at Machida how he beautifully incorporates karate in MMA game.
So how does the tooling problem get solved? This would seem to be the limiting factor presented in the article not necessarily how opinionated the language is.
Of course JavaScript has some pretty severe limitations as far as functional programming goes, the biggest being really cumbersome lambdas, and a lack of implicit return. If you try to program in a functional style in JavaScript you'll be fighting the language more than you'd like. However both of these issues are remedied in CoffeeScript.
As someone who was a lisper before getting into web development I'm really surprised to see lambdas, closures, pattern matching/de-structuring bind, let statement equivalents and more be part of a language that is not even talked about too much as being lisp-like or functional. Also important is that CoffeeScript's main selling point is that it's practical and more sane then JavaScript, not that it's functional or lisp-like. At the same time CoffeeScript is probably the closest thing I've seen to a (potentially) successful lisp-without-parens
Functional languages will gain serious traction, but I think it will be when their users find their features convenient and helpful (coffeeScript) rather than interesting/mind-blowing/etc (scala, haskell, erlang..)