4 ms·
I like to tell people that the killer app for Haskell is writing IO bound, asynchronous code. The secret weapon is do-notation, which lets you write code as if
by ezyang 10y ago
I like to tell people that the killer app for Haskell is writing IO bound, asynchronous code. The secret weapon is do-notation, which lets you write code as if it were sequential, but have it desugar into what is (essentially) a series of chained callbacks.
I like to point at Facebook's use of Haskell as a good example of being successful in this space http://community.haskell.org/~simonmar/papers/haxl-icfp14.pdf http://community.haskell.org/~simonmar/papers/haxl-icfp14.pd... It would be disingenuous to suggest that Haskell is good in all situations, but if there was one place where it should be used, this it.
- quotemstr 10y agoHaskell is good for lots of things, but I don't see it being particularly powerful in this application. The IO monad and do-notation let you write sequential code. So does Python. ¯\_(ツ)_/¯
- ezyang 10y agoThere are two responses here. The first is that in any language which has any sort of threading model at all, sequential code in multiple threads obviates the need for callbacks. If you block, fine; it's just a single thread, it's not obstructing the handling of other threads. Why don't Python and JavaScript have multithreading? Well, because programming with unrestricted concurrency and mutable state is really difficult. But there are ways to solve this problem, Haskell's purity being one among several. The second is that do-notation is distinct from the IO monad. Even if Haskell didn't have green threads in the runtime, I could still write an async/callback library that looked just as natural as sequential code. Why? It has nothing to do with the IO monad: it has to do with the fact that "do x <- e; m" desugars to, in JavaScript notation, bind(e, function(x) { m }); it's been "callbackified automatically".
- quotemstr 10y ago> could still write an async/callback library that looked just as natural as sequential code You can do that in any language with AST transforms powerful enough to transform code into CPS. That functions are "automatically callbackified" is an implementation detail and not one particularly germane to high-level code.
- rtpg 10y agowell that's kind of the point isn't it? That Python doesn't offer this, and that Haskell is one of the few production-ready tools that offer this in a clean way?
- quotemstr 10y agoWho cares how it's implemented? Python lets you write straight-line code that does more than one IO-bound thing at a time. So does Haskell. That one is using a CPS transform under the hood and the other stack-switching via OS threads is irrelevant.
- rtpg 10y agoit's not exactly the same. Python lets you write straight-line code, but you still have to be explicit about the sync/async nature of each call. You can abstract this away in Haskell, thanks to some interesting tooling around `do` notation. Some people prefer the explicit nature though.
- marcosdumay 10y agoHaskell does not even allow one to write sequential code. The IO monad enforces sequence on IO operations, and when you fork it, you get a new, independent sequence of IO operations to play with, not a new thread. Haskell is really great for concurrent programming. Not only because of green threads (the mainstream concept that is nearest to the IO monad), but because of the "everything is immutable" rule, and very powerful primitives available.
- rkangel 10y ago> The IO monad and do-notation let you write sequential code It's actually much subtler than that due to lazy evaluation. The 'palindrome' section of http://learnyouahaskell.com/input-and-output http://learnyouahaskell.com/input-and-output illustrates this. You basically write code that says: read all input, split lines, do something per line, join result into multiline string, print. If you did that in Python it would block until EOF on the input and then print the result. In Haskell, due to lazy evaluation you will interactively get the response on a per-line basis. What Haskell really gives you is a declarative language to describe what you want to happen to some data and then the lazy evaluation sorts everything out. Underneath, it's effectively a load of callbacks processing data streams.
- tome 10y agoYeah but that's lazy IO, and is highly frowned on, even considered a historical mistake.
- runeks 10y agoI would argue that the Haskell language itself, through lazy evaluation, basically has built-in async/await support. Due to lazy evaluation, everything is a async/await - every time an expression is evaluated. In Python, you pass values around. In Haskell, you pass around descriptions of how to fetch a particular value, and then the runtime system makes sure it happens when/if it needs to. It's a bit like Excel. Every cell is a variable that contains an expression, which defines what this cell evaluates to. With that description in hand, it's a simple matter of not evaluating cells that are not in view, and marking an exception in the evaluation with #######. If it were Python, each cell could contain code that modifies other cells, and it would be impossible to make sense of anything.