lauantai 6. maaliskuuta 2010

The pure lie of Haskell (ghc)

When I stumbled upon Haskell, I was so impressed with the concept of its purity. Functions that don't have IO types in their signature, are guarenteed to be side effect free, and are called pure. You can trust that when you evaluate a pure function with the same arguments, you will always get the same result and that nothing suspicious happens under the hood, e.g. ejecting DVD out of your computer.

Here's a quote from Real World Haskell (which is great, btw).
Haskell strictly separates pure code from code that could cause things to occur in the world. That is, it provides a complete isolation from side-effects in pure code. Besides helping programmers to reason about the correctness of their code, it also permits compilers to automatically introduce optimizations and parallelism.

That is what most Haskellers brag about. But they don't mention that in the (only?) viable industrial strength compiler (GHC) let's you to by-pass this with evilness called unsafePerformIO

Its type is IO a -> a  
Basically, it let's you to perform an IO action in an pure context. Also, it's not even type safe as the documentation points out.

I must say I have been quite angry once I found about this, although it doesn't seem to concern others as it doesn't affect much the everyday use of the language.

I think it would be nice to have a compiler option for checking that unsafePerformIO or any other hack is not present in any used code path. This would be important for example when one setups a public environment to evaluate Haskell code. It also would drop the risk of getting malicious code from open source library you are including in your project without the need to manually check (or grep it).

Of course, I'm not denying the need for unsafePerformIO, it's just that it ruins the whole beautiful idea in one quick shot. There is no way to enforce pureness because of it.

One way to make the situation better would be to require modules to explicitly document functions that (transitively) are using backdoors. That way the type system would work as always, but at least people would know the risk via documentation.

At least, the morally right thing to do would be to mention unsafePerformIO when one introduces Haskell, as it's a little cheap to sell something that isn't there. Luckily, the separation of IO and pure code is still very useful in practice as it guides to better division of programs, and one needs to be explicitly aware when she's breaking the rules.

Ei kommentteja:

Lähetä kommentti