Hacker News new | ask | show | jobs
by chousuke 4778 days ago
It is referentially transparent. The lambda (or thunk) itself can be used freely as a value. For example

  newtype PureIO a = PureIO (() -> a)
  print :: String -> PureIO ()
  print s = PureIO $ \_ -> unsafePrint s -- impure primitive
If the user only has access to the "print" variable, then they can only use it as a pure value. two applications of print "foo" would result in two thunks, either of which, when actually invoked, would cause the side-effect of printing "foo".

Invoking the pure IO values is something only the runtime can do, so referential transparency is not violated.

1 comments

The important thing here is not the wrapping with a lambda. That's not what made it pure.

The important thing here is the abstract type wrapper. You're exposing pure primitives that are implemented in terms of (hidden) impure ones.

That's why code that uses unsafePerformIO can be pure and referentially transparent, as long as the exposed primitives are pure and implementation details are hidden.

To demonstrate this, imagine that you did expose the PureIO data constructor -- then values of type PureIO would not be referentially transparent anymore.