haskellfunctional-programmingtype-systemsreferential-transparencyunsafe-perform-io

Is Haskell really a purely functional language considering unsafePerformIO?


Haskell is generally referenced as an example of a purely functional language. How can this be justified given the existence of System.IO.Unsafe.unsafePerformIO ?

Edit: I thought with "purely functional" it was meant that it is impossible to introduce impure code into the functional part of the program.


Solution

  • The Languages We Call Haskell

    unsafePerformIO is part of the Foreign Function Interface specification, not core Haskell 98 specification. It can be used to do local side effects that don't escape some scope, in order to expose a purely functional interface. That is, we use it to hide effects when the type checker can't do it for us (unlike the ST monad, which hides effects with a static guarantee).

    To illustrate precisely the multiple languages that we call "Haskell", consider the image below. Each ring corresponds to a specific set of computational features, ordered by safety, and with area correlating to expressive power (i.e. the number of programs you can write if you have that feature).

    The language known as Haskell 98 is specified right down in the middle, admitting total and partial functions. Agda (or Epigram), where only total functions are allowed, is even less expressive, but "more pure" and more safe. While Haskell as we use it today includes everything out to the FFI, where unsafePerformIO lives. That is, you can write anything in modern Haskell, though if you use things from the outer rings, it will be harder to establish safety and security guarantees made simple by the inner rings.

    alt text

    So, Haskell programs are not typically built from 100% referentially transparent code, however, it is the only moderately common language that is pure by default.