Hacker News new | ask | show | jobs
by Peaker 4781 days ago
"Pure" typically means referentially transparent. Wrapping a side-effecting procedure in a lambda does not make it referentially transparent, therefore it isn't pure.
1 comments

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.

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.