I have to agree with the other guys here: The article doesn't seem to take recent functional languages (and their rise in usage) into account.
To write as little BS as possible I mostly keep myself limited to F#, a language I know:
- You don't need to use formal proves to design your software, the "purity" of your code is up to you
- Stacktraces? Hell, yeah.
- IO: Use what the .Net framework gives you - it's not that different from other .Net languages and you can isolate these side effects nicely in a simple method or go down the monad path..
In short: I disagree with the article, because I have made quite different experiences in the past. The morale of the story: Don't be too general (functional programming) if you have trouble with specific things (like Haskell's academic background).
Because nobody has mentioned Erlang yet, I should point out that CouchDB, Riak, and RabbitMQ are all written in it. They seem to be holding their own when it comes to practicality.
Erlang is a functional programming language without so much as a single iteration construct; if you want a loop, you have to use recursion. Variables are immutable, and it communicates via asynchronous messages between lightweight processes.
Just some clarifications so that newbies don't get scared away from erlang :)
Erlang is a functional programming language without so much as a single iteration construct; if you want a loop, you have to use recursion.
To keep it from sounding too terrible, Erlang has all the standard map/foreach/fold functions that every other functional language has; it's all recursion at the bottom, but it's nicely encapsulated. Most data structures follow the conventions of the iteration functions found in the lists module: http://erlang.org/doc/man/lists.html
Variables are immutable, and it communicates via asynchronous messages between lightweight processes.
I don't know if couch, riak, or rabbit use them, but erlang does have the process dictionary, which is a per-"thread" mutable datastore (http://www.erlang.org/course/advanced.html#dict). I know that wings3d uses the process dictionary a lot, supposedly for performance reasons. The use of the process dictionary isn't recomended, but it is there when needed.
EDIT: corrected an instance of rabbit where I meant erlang
Erlang also has convenient features like list comprehensions and partial definitions of functions to make this stuff easier. And while the process communication stuff is supposedly a distribution/concurrency system, you can treat processes as objects and do message-passing style OOP with a little cleverness.
I don't feel that this post is fair. You can't say "we can't do solve real world tasks with functional programming because Haskell isn't practical."
I'm sure this isn't a fair analysis either, but I think it's an accepted belief that pure functional languages don't fit with how the world works. That doesn't mean that functional languages with side effects (multi-paradigm is probably the correct term) like Lisp, given the recent rise of Clojure, or F# can't be used in the real world.
> That doesn't mean that functional languages with side effects
Haskell has side-effects too, you know. The point of Haskell is not to eliminate side-effects entirely, but to have a static separation between functions with side-effects and functions without through the type system.
Add on another "this seems overly simplistic" vote here. I've actually been playing around with writing a Roguelike in Haskell over the last few weeks. My code is super-noobish, but it's working fairly well.
Just because it's different doesn't mean that it can't be done.
There are some things that are easier to do efficiently with imperative languages. And one can generally easily write functional code in a modern imperative language (C# for example has many, if not most, of the tools available in popular functional languages). But less easy to do imperative in a functional language.
Multiparadigm languages are here now and feel like the future.
Multiparadigm languages are here now and feel like the future.
This is one answer to the problem raised by the article: certain things (like I/O) are less natural to do in a (purely) functional language, so a language which supports multiple paradigms can get the best of many worlds.
Another answer would be to have better language integration, so that it would be totally trivial to, say, write the purely functional pieces of a system in Haskell, and hook them up to I/O code in an imperative language, a GUI in an object-oriented language, whatever. That way, the implementors of a given language could focus on supporting a single set of strengths, without having to provide foreign-feeling or half-assed devices for doing things that aren't natural to do in that language.
Of course, this is an extremely difficult problem to solve, at least after-the-fact: once you have two languages that were designed without a specific plan for semantic integration with others, just passing simple data types between them can involve intractable difficulties. Thus, platforms which provide a common "metalanguage" are needed to make language integration more tractable. My impression is that we are seeing such platforms grow in both popularity and sophistication (e.g., the JVM), and accordingly seeing a rise in the popularity of languages that focus on a single paradigm but provide easy (or easier) integration with other languages on the same platform.
"There are some things that are easier to do efficiently with imperative languages. And one can generally easily write functional code in a modern imperative language (C# for example has many, if not most, of the tools available in popular functional languages)."
Really? When did they add pattern matching, algebraic data types, and reliable tail call elimination?
Reality is that imperative languages provide about as much support for functional programming as functional languages have for imperative programming: just enough to get by. And I would even say this is a good thing (perhaps excluding lisp: it can do everything due to sheer elegance rather than due to bloat).
"Really? When did they add pattern matching, algebraic data types, and reliable tail call elimination?"
I didn't say all features. In fact I said "has many, if not most". I was trying to be explicit that not all features that exist in every functional language exist.
Now with that said, the specific features you list, while popular, weren't widely considered "necessary" features to be classified as a functional language. For example, Scheme has neither pattern matching nor ADTs. Although I'll grant you that for modern functional languages its near a prerequisite. And AFAIK tail call elimination is less a function of the language, and more of the implementation (and I'd argue to the extent that you write in a functional style, many/most production quality compilers of imperative languages will do this optimization). Of course I could be wrong and maybe some functional languages define in their spec exactly when tail call elimination must invoked.
If you look at what is commonly the crux of functional languages you'll see things like:
* Recursion -- yes, there was a time imperative languages didn't support recursion. So when they were arguing Lisp vs Fortran this was relevant. Now this seems like such a passe feature of all languages, but I think its worth point out.
* First class functions.
* Lambdas and closures
* Immutable data
* Pure functions
* ADTs or other interesting type systems
And there are some second order features like list comprehensions.
Again, I think if you go through this list, you'll see that modern imperative languages capture a lot of these features. Not necessarily all of them, but I have discovered that I've been able to do some relatively straightforward ports of functional algorithms, keeping all of the functionalism intact.
I think this post doesn't recognize that you should match the problem you are solving to the paradigm you are using. Functional programming is extremely useful for many types of financial analysis, and other big data problems like pattern matching and data verification. Sure- you might not want to write a mvp for a lean webapp in Ocaml, but saying people don't use functional programming anymore is just not true.
I strongly disagree. If you're expecting the first value of a list, what use is nil?
If you have a list of Ints, then what can you do with nil returned? It's not an Int.
Nils have a habit of propagating through the whole type system, and you then need to have rules about how they apply to every function. (What is 1+nil? What is nil:[1,2,3]?).
Eventually every single function will either have odd behaviour when confronted with a nil, or will be a source of exceptions (which are generally undesirable in a pure functional setting).
Haskell encourages you to write patterns that check for these edge cases, and handle them explicitly:
Why would you have nil in a list of integers? In cases where you encounter nil instead of some type you look for you can add behavior to nil without doing if nil? in the function all the time.
I would agree that not having nil is better if you have these big typesystems but for a dynamic languge its hard to avoid.
Question: Don't these static langauge use "unit" to signal what nil would do in clojure (in some casses)?
To write as little BS as possible I mostly keep myself limited to F#, a language I know:
- You don't need to use formal proves to design your software, the "purity" of your code is up to you
- Stacktraces? Hell, yeah.
- IO: Use what the .Net framework gives you - it's not that different from other .Net languages and you can isolate these side effects nicely in a simple method or go down the monad path..
In short: I disagree with the article, because I have made quite different experiences in the past. The morale of the story: Don't be too general (functional programming) if you have trouble with specific things (like Haskell's academic background).