This is the first of a set of posts on what we need from a new programming language. Everything I discuss exists in some language -- at least in part -- but no language yet has them all. This content is a mixture of my experience and many borrowed ideas, which I will do my best to cite. My goal is to represent the language needs of some segment of developers.
The Metaphorical Mind
I'll start simply: a language must be designed and taught with its users in mind. There is a psychology to programming which may explain why some languages get adopted and better ones don't. To model this psychology, I borrow the idea of the "Metaphorical Mind", as described in Steven Pinker's excellent How the Mind Works. In Pinker's words, "The human mind, we see, is not equipped with an evolutionarily frivolous faculty for doing Western science, mathematics, chess, or other diversions." Our minds evolved to work with the physical world, and we reason with abstract ideas using physical metaphors. Pinker cites Ray Jackendoff for examples:
The messenger went from Paris to Istanbul.
The inheritance finally went to Fred.
The light went from green to red.
The meeting went from 3:00 to 4:00.
(emphasis in original)
The first sentence shows physical movement; the others use the same terms but have nothing moving. Beyond movement, spatial metaphors permeate our thoughts and language. "The meeting is at 3:00", for instance. In fact, it's hard to describe almost anything without physical metaphors.
Many examples exist in software. Imperative programmers deal with pointers, objects, stacks, messages, events and so on. Our secondary storage uses folders, files and paths.
In fact, there is an alarming predictability on language adoption: languages that strengthen the physical metaphor -- or at least solve problems without weakening it -- have found widespread use. Languages with weaker physical metaphors remain with a small base. Compare the adoption rates of object-oriented languages to their functional counterparts.
This might be an indictment of functional languages, since they are typical expressed in abstract mathematics rather than physical analogs. That is unfair. Functional languages can be built and explained in straightforward physical terms -- they just aren't. Take, for instance, Haskell's Monad. I've written only small programs in Haskell, but for my purposes it's much easier to think of a Monad as a "to-do list". (Some use the term "action". I know it's an over-simplification, but that's the point.) The bulk of the language is a means to construct to-do lists in isolation. Put in these terms, Haskell can be simpler than many languages -- the functional purity eliminates all kinds of moving parts imperative programmers have to worry about.
This is a good step, but widespread adoption means more than renaming of concepts. Unfortunately, programmers who find and learn functional languages are not representative of the population. I'm afraid we would lose a broader audience in the first hour of learning Haskell, as soon as they got to this:
fibs = 1: 1: zipWith (+) fibs (tail fibs)Beautiful, isn't it? One line of code for Fibonacci numbers, what amounts to built-in memoization, the ability to get and manipulate any sequence, and so on. But it also has only the weakest of ties to a physical analog. Non-trivial examples are much harder to understand. Sadly, an incredibly powerful tool for some is simply too abstract for others to use effectively.
Because of this and other examples, I doubt Haskell will ever be widely used despite all of its advantages. But this is okay -- we need powerful tools for the hands of experts. What I want to see is a more accessible language borrowing the best ideas from Haskell and others. I wish I could use Monads every day, and am willing to sacrifice some of Haskell's other power to achieve this.
This raises an important question: shouldn't we raise our expectations of developers rather than take away powerful features? A valid point, which I will tackle this in my next post. For now, the central thesis of these posts should start to emerge: we need a language with the best parts of Haskell and others in a more accessible form.
8 comments:
I think you'll find that scala embodies the traits of Haskell that give it it's essential elegance, such as pattern matching, list comprehensions, monads and the like, along with ruby-style blocks and object-orientation, all seamlessly integrated with Java.
From what I've read, there's a lot I like about Scala. The only big drawback for me is its functions can have side effects by using other languages, so it doesn't offer the strength of guarantees that Haskell does. (For instance, I can't assume the same inputs will always have the same effect, and I can still have race conditions in my code.)
Now, it may turn out those strong guarantees aren't practical for a general-purpose language, but I'm still hoping we can have the isolation and safety of Haskell in a simpler form.
Think zipper. It's a list of one and one and a moving zipper that joins the teeth of two lists (itself and itself shifted by a place) by a simple addition. You can almost see it move, sucking itself in and emitting itself! I find Haskell is the most physical language. Flows, mergings, expansions - it feels like a conveyor belt.
It's not so much the zipWith function that lacks the physical metaphor -- it's the infinitely long list defined in terms of itself. Particularly, the tail function embedded in there returns the tail of an infinite list that is still being constructed. Not saying this isn't understandable, but I have trouble mapping it to anything in the physical world.
You could say the same thing about a recursive function defining Fibonacci numbers, but these are more explicit. "Add the last two numbers on the list to get the next one", to me seems more understandable.
Nice post. I have decided something similar in language design - concrete is easy, abstract is powerful.
As for infinite lists, well, they're not really infinite. Combined with lazy evaluation, a physical metaphor becomes aparent - it's like a factory which always meets its demand. I suppose a difference here is the recursion aspect.
Scala has recently adopted (version 2.3.3) adopted the Erlang model of concurrency (via library) so that might be an additional reason to consider it the mainstream language that comes closest to meeting your requirements.
http://bymyreckoning.com
Thanks for the nice post!
Free PS3
Post a Comment