Hacker News new | ask | show | jobs
by advocaat23 4268 days ago
Is it concerning that most Haskell optimization guides talk about adding ! to enforce evaluation? It may be a sign that pure functional programming is not quiet there in the real-time world (e.g. real-time rendering) and that some abstractions (declarative instead of imperative) break for these use-cases.

What I want to say is that you really have to know a lot about Haskell to predict a program's runtime performance which is essential in the context of real-time. In my opinion these optimizations seem a little bit hacky: unsafePerformIO is per definition hacky, she-bangs seem sometimes like guess-work and concurrency is always hard to get right (even with MVars).

I really like Haskell but do not consider it yet for latency-sensible tasks as it feels like writing unidiomatic Haskell. In particular I find it concerning that one has to exploit concurrency and parallelism for such a simple game.

Are their ambitions to make GHC (hard) real-time friendly? This will probably require a real-time GC optimized for latency. I would like to read more about this, in particular about using pure (strongly typed) functional languages in a low-level/real-time context. Would it be possible to exploit the type-system there?

5 comments

In a conventional language you have to decide when something gets evaluated, and whether to cache the value or recompute it every time. These decisions get baked into your code early on because the control and data flow are intertwingled.

In Haskell you just specify the data flow and the compiler looks after the control flow. Sometimes the compiler's default idea is less than optimal, so you can tweak it by adding bangs and other strictness annotations to the code. The semantics change slightly because maybe now you evaluate an expression that throws an exception or goes into an endless loop, whereas before it wasn't evaluated, but apart from that the changes are guaranteed not to affect the meaning of your code.

Sure, garbage collected languages are not suitable for hard real time, but interactive apps and games are soft real time (a 100 ms delay once per hour isn't going to break the game). GHC is already there.

Your first paragraph is about laziness-vs-strictness, not functional vs imperative. Most Haskellers would agree that laziness is probably the least important benefit of the language.

It is true that the flip side of GHC's impressive optimizations is the performance of code is harder to reason about just by looking at it. One could argue that this is an simply unavoidable downside of having powerful optimizations -- the simpler the compilation process the easier it is to reason about performance.

Last I checked one can simply import a foreign function as pure, so they wouldn't need unsafePerformIO. Still, I wouldn't consider applying unsafePerformIO to a function that actually is pure a hack.

Regarding (hard) real time, check out http://stackoverflow.com/a/1267814 . Keep in mind that is 2009 so the state of things today could well be a lot better.

As it turns out, in practice, you usually want your data structures to be as strict as possible, but your control flow to be as lazy as possible. Further, some code just isn't well-suited to laziness -- so much so that there's work afoot to have a "strict-by-default" LANGUAGE pragma added in GHC 7.10.x[1].

[1] https://ghc.haskell.org/trac/ghc/wiki/StrictPragma

> you usually want your data structures to be as strict as possible, but your control flow to be as lazy as possible

That's a very nice slogan. I'll have to remember that. It certainly covers the case of generally wanting your record fields to be strict and lists to be lazy when used for control flow.

> That's a very nice slogan.

Yeah, I borrowed it from some Haskell luminary. My search-fu failed me so I didn't source it as I should have. :)

It's not a sign about pure versus impure functional programming. It may be a sign about strict versus lazy evaluation.
Nevertheless I heard (I should investigate this rumour) that being lazy enabled an easier integration of the IO system so there seems to be a connection between pure (i.e. side-effect free) and laziness.
Perhaps you're thinking of the observation that laziness essentially forced Haskell to be pure (otherwise the order of side effects is very difficult to control) and thus led to the invention of monadic IO.

If you're thinking of something else please do report back if you investigate as I would be interested to know.

They chose to make Haskell a lazy language and that forced them to make it pure. You cannot have laziness without purity.
You can, but you'll really hate it :)
> Is it concerning that most Haskell optimization guides talk about adding ! to enforce evaluation?

No, it's not. It's a perfectly reasonable consequence of Haskell's design choices.

> What I want to say is that you really have to know a lot about Haskell to predict a program's runtime performance

And you really have to know a lot about CPUs to predict cache locality issues in C/C++ programs. This is to be expected.

Austin Seipp, one of the core contributors to GHC, has a really good writeup about this in the comments over at the haskell subreddit for this same article.

http://www.reddit.com/r/haskell/comments/2jbl78/from_60_fram...