Haskell 2010 Announced
paltemalte writes "Simon Marlow has posted an announcement of Haskell 2010, a new revision of the Haskell purely functional programming language. Good news for everyone interested in SMP and concurrency programming."
← Back to Stories (view on slashdot.org)
And all three of its users are overjoyed.
So I don't think I'll look at the article until I actually need to program in Haskel....
Test your net with Netalyzr
Functional languages are enjoying an enormous renaissance in the field of multithread, multicore and/or multiprocessor environments.
There are a few really major obstacles to doing multi-* well. The major theoretical one is Amdahl's Law, which puts some extreme limits on how much multi-* can help you. The major practical one is our current obsession with side-effect languages. We need major theoretical advancements to get past Amdahl's Law (if, in fact, it can be gotten past at all). Functional programming is a great way to get past side-effect-based programming, though.
In a proper functional language, there is no such thing as iteration. There can't be. The instant you say, "each time through the loop, increment the counter, and as soon as it hits this certain value stop," you have stopped programming in a functional style.
As an example of some really cool concurrent languages that emphasize recursion and functional programming, look at Clojure, Scala, Erlang and F#. All of these languages provide iteration and other side effect techniques if you really need them -- but all of these languages emphasize recursion.
They figure if they make it good enough, more than one person will code in it at a time.
Welcome to the programming language department. Bruce here teaches Python, the object oriented dynamically typed language. Bruce teaches Python the lazy functional language, while Bruce teaches postfix Python. And then there's Bruce who teaches s-expression Python and is in charge of the snake dip.
there is no god but truth, and reality is its prophet
Well, pure functional languages are (potentially) good for concurrency in general. Because they have no mutable variables in the usual sense, it doesn't actually matter what order functions are evaluated in (other than the fact that callers cannot continue until their callees return). You can't do this in C or Java because it might be necessary for one function to see a variable modified by another. In a functional language, any dependencies are explicit call-return relationships (well, ish, they typically do have some non-functional constructs otherwise it's hard to do IO!), so in principle it's quite easy to split up a program's work across multiple CPUs (or machines) and not worry about whether they need to talk to each other.
Haskell, along with the ML family of languages, also has an amazing type checker that is waaay more sophisticated than most other languages. I think most people who've played around with these languages do start to feel that often "If it compiles, it's bug-free". Obviously that's not something you can rely on, since the compiler can't know what you meant to do. But it is true that the type system is *way* more useful at detecting bugs at compile-time than for any conventional language I've used.
Most procedural programming languages use (or at least support) recursion, too. The difference is that (1) pure functional language cannot express certain algorithms with iteration instead of recursion because of the lack of mutable state, and (2) languages that don't support tail call optimization (at least in the trivial case of self-recursive tail calls) generally also don't efficiently support recursion, since recursion results in the accumulation of stack frames. A consequence of #1 and #2 is that pure functional languages almost without exception, as well as many less purely functional languages that designed to support programming in a functional style (e.g., Scheme), feature tail call optimization and have tail-recursive constructs as the most idiomatic way of expressing certain algorithms, whereas languages that aren't functional or designed with functional-style programming in mind, often have an iterative approach as the most idiomatic -- and most efficient -- expression of the same algorithms.
Amdahl's law is not like Moore's "law". Amdahl's law is an observation of mathematics. You can't ever get around the fact that if you increase the performance of 90% of the instructions in a program, you still have to deal with the other 10%. Even if you increase the performance of 90% of the instructions by 100x or something large, if the other 10% take a long time (like disk access) its going to kill your performance.
Erlang and Scala are both languages designed to support programming in a functional style, and both are "recursive style" languages in that they optimize tail calls generally (Erlang) or at least in the most important case of self-recursive calls (Scala) and thus make tail-recursive (or, in Erlang's case, more general tail calling with unlimited depth) programming styles efficient.
Neither is a pure functional programming language, true.
I would add a couple other "must have" features in functional languages:
* The ability to pass a function as an argument to another function (i.e. higher order functions, like qsort in the C standard library).
* Support for a points-free programming style in which things can be passed from one function to another without naming them.
Some other features that perhaps aren't technically required but make functional programming a lot easier:
* Closures, local function definitions, garbage collection, partial evaluation of function.
"recursive style" Definition: Curse. And then curse again.
Let's see if I can explain this simply.
The Haskell language, like any other language, needed constructs like "read" and "write", but to implement them as simple functions would have broken the underlying assumptions of purity and lazy evaluation.
Haskell happened to have monads. A monad is essentially a typeclass for containers, that allow you to do certain things to combine containers of the same type, without having to worry about what kind of container it is. Most (all?) of the containers in the standard library are instances of Monad.
The Haskell language designers came up with (or perhaps borrowed) an idea. They would create a new container type, called IO, and make it an instance of Monad. However, unlike other containers, it would not have any accessor functions. You can pass around an object around of type IO in pure code all you want, but you can't ever examine the contents of the IO container from within "pure" code. The only thing you can do with it is combine it with other IO objects. Combining two IO objects is equivalent to evaluating the file operation or what have you inside one IO object and passing it's result to and executing whatever is inside the second IO object. The actions within an IO object, however, are free to invoke pure code if they like.
Every haskell program has a main() function, which is an IO action. This allows you do do any necessary file IO your program needs to do, and it can also call out to pure functions. Pure function cannot invoke IO actions. Most Haskell programmers try to keep the IO actions as simple as possible and rely on pure code for the bulk of the program.
As a concrete example, I wrote a ray tracer, which parsed a text file and generated an image. As I was writing it, I got to the part where I needed to write the file parser. I thought "oh, no, this whole thing has to execute within the IO monad and it'll be a big mess". However, it was not so. After scratching my head a bit, I ended up writing a pure function that takes a simple text string and converts it to my internal representation of a scene, ready to be ray traced. Within main (within the IO monad), I would read the text file in with a lazy function "hGetContents", which returns a string which is the contents of the file. I would pass that string to the parser, and then trace a grid of rays (one per pixel) against the parsed scene. The list of pixels with their calculated color values was returned to the IO monad, where I used OpenGL to plot them to the screen.
The interesting bit about this is that hGetContents is lazy. In a strict (i.e. non-lazy) implementation, the whole string would be read at once. This is inefficient, and may cause problems for text files that won't fit in memory. Due to laziness, however, the string is passed into the parser without being fully evaluated. As the parser needs more data, the run-time system will cause hGetContents to read another block. So, here we have an example of a pure function that's indirectly triggering IO, and it's doing it all without violating the constraints of the type system.