

How to write a simple TCP Server in Haskell - pkrumins
http://catonmat.net/blog/simple-haskell-tcp-server

======
jerf
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.

~~~
bretthoerner
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?

~~~
jerf
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

    
    
        line1 <- hGetLine handle
        line2 <- hGetLine handle
        line3 <- hGetLine handle
    

(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.

------
athesyn
Are there similar productions of this, for other languages? It'd make a great
point of reference./

~~~
synacksynack
Racket has a similar sort of tutorial in its official documentation.

<http://docs.racket-lang.org/more/>

------
JohnJacobs
if your interested in event-driven programing you should try sxe
<http://simonhf.wordpress.com/2010/10/09/what-is-sxe/>
<http://github.com/jimbelton/sxe>

------
skybrian
It's all imperative code. Would someone who really knew Haskell write it
differently?

~~~
jmillikin
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.

