And this can run on all your cores (I don't know if it does as shown but it would be a command-line param to ghc if not), and is "async" without requiring the commandProcessor function to be broken into two or three separate functions by hand; instead it just says what it does and does what it says and you don't have to worry about it.
I understand how Haskell can use the cores automatically, but can you point a lower being like myself at some documentation or even terms to figure out how this becomes async for free?
Haskell's forkIO uses green threads, which means you can have thousands (or even 100k+ if they are mostly blocking on IO). Haskell's runtime and green thread scheduler (at least those shipped with GHC) uses select (and in GHC7 kqueue/epoll) to avoid blocking your OS threads on IO. So basically the runtime gives you lightweight (green) thread multiplexing for free when using forkIO.
You've basically been lied to about "async" in the past few months, or at least led on by ignorant people; the word used to mean something but there has been a concerted effort to screw up its meaning. When you write in Haskell
(Which is not quite the exact same thing shown, I'm showing an example here.)
This will get three lines. These lines may not come right away; someone could be using Telnet to send them for debugging purposes, for instance. The Haskell scheduler automatically notices the socket is blocked and puts the thread away until there is enough input to finish the line. It may even end up reading the line from many packets. Once it is ready, control returns to your code, then it may do it again for line two. At no point will the main OS process be "blocked"; you can have a ton of these running simultaneously, all waiting at different points. The language and runtime simply take it in stride.
That you may have to manually chop code up into a series of callbacks because of the limitations of various technology stacks is one thing. I've had to do that too. The way this has been promoted in some circles as the only right way to do it is absolutely bizarre. No, it's not right. You should be able to just write your code and not be responsible for manually scheduling it. Compilers and the runtime can do that for you, and it's actually easier for them.
The lie I referred to is that the source code I show must be synchronous because you don't see the points where it is chopped into little bits. The truth is that this is perfectly possible to do automatically in any number of ways, and that code is at least as "asynchronous" as Node.js code (and possibly more so, depending on the implementation of "get one line"). This isn't a special Haskell feature, either, numerous other good languages can do this, Erlang, Go (I'm pretty sure), Stackless Python, Lua (I think), and that's not even a complete list.
Furthermore, it's not only asynchronous, it's a superior type of asynchronous. This code maintains execution context way better than any manually chopped up "asynchronous" code could. If the code I showed was in the local equivalent of a "try" block, the exception would actually work as you expect; whether the first, second, or third call fails, they could all be handled by the same try block, exactly as the source code would show. If I got a stack trace (in one of the other languages I mentioned where "stack trace" means something, in Haskell it's a bit... trickier), it would be completely sensible. The composability of code written this way is far, far superior to manually-chopped up "asynchronous" code, because functions can simply take other functions as arguments without having to care whether those functions themselves may have asynchronous components to them.
Fun task, try converting the following psuedocode into Node.js losslessly, with only one "try" and no duplication:
function readTwoLines():
return [readLine(), readLine()]
function readLineAndDie():
readLine()
throw NoLines("No more lines, I think")
function doThings([functionList]):
# 'call' just applies the function
try:
return map(callFunc, functionList)
catch NoLines:
return null
function main():
a = doThings([readTwoLines, readTwoLines])
b = doThings([readTwoLines, readLineAndDie])
print a, b
That's should consume 7 lines, and print a list containing a list of the first two lines, then a list of the third and forth lines, then print a null. It may be possible, but you won't like it.
Haskell works well for both declarative and imperative styles. I would make some small changes ('forever' instead of explicit recursion, less duplicate code in handlers), but it would be basically the same.
There are a few Haskell web frameworks out there which take advantage of advanced Haskell features. The Snap framework is based on Iteratees, a fairly recent abstraction developed for Haskell IO. The source code is readable, though you want to make sure you understand iteratees first.
Don't fix what ain't broke. The more I grok Haskell the more I believe its not only a solid functional language but also my favorite imperative language...
Based on what usage/performance you expect you could maybe take a different approach, but for a simple and general TCP server example I don't see a reason to do anything different except maybe minor style details...