On 29/12/2011 19:26, Heinrich Apfelmus wrote:
Steve Horne wrote:
Heinrich Apfelmus wrote:

Again, purity refers to the semantics of functions (at run-time): given the same argument, will a function always return the same result? The answer to this question solely decides whether the language is pure or impure. Note that this depends on the meaning of "function" within that language. In C, side-effects are part of the semantics of functions, so it's an impure language. In Haskell, on the other hand, functions will always return the same result, so the language is pure. You could say that side effects have been moved from functions to some other type (namely IO) in Haskell.

Anyway, if you're using IO actions, your code is not referentially transparent and is therefore impure - by your own definition of "impure". Causing side-effects may not be pedantically the issue, but the mix of causing and reacting to them - ie interacting with the "outside" - clearly means that some of your function results are dependent on what's happening "outside" your program. That includes side-effects "outside" your program yet caused by program program.

No, that's not my definition of "impure". Also, my Haskell code is referentially transparent even though I'm using IO actions. If this sounds paradoxical, then it's probably worth mulling about some more. Maybe it helps to try to find an example of a function f :: A -> B for some cleverly chosen types A,B that is not pure, i.e. does not return the same values for equal arguments.
That doesn't prove Haskell pure.

Of course your challenge looks like a safe one. It can't be done because the IO monad is a black box - you can't e.g. pattern-match on it's data constructors.

Of course you can extract values out of IO actions to work with them - the bind operator does this for you nicely, providing the value as an argument to the function you pass to the right-hand argument of the bind. But that function returns another IO action anyway - although you've extracted a value out and the value affects a computation, all you can do with it in the long run is return another IO action.

Even so, that value can only be extracted out at run-time, after the action is executed.

So, consider the following...

getAnIntFromTheUser :: IO Int

From a pure functional point of view, that should return the same action every time. Well, the partially evaluated getAnIntFromTheUser has the same structure each time - but the actual Int packaged inside the action isn't decided until runtime, when the action is executed. At compile-time, that action can only be partially evaluated - the final value OF THE ACTION depends on what Int the user chooses to give because that Int is a part of the action value.

For your specific challenge, place that as a left-hand argument in a bind...

f :: Int -> IO Int
f = getAnIntFromTheUser >>= \i -> return (i+1)

Well, the value of i isn't decidable until runtime. The value of i+1 is not decidable until runtime. The value of return (i+1) is not decidable until runtime and so on. It can only be partially evaluated at compile-time, but when it is fully evaluated, you get a different IO action returned by f depending on what Int you got from the user.

And so we get right back to the referential-transparency-by-referencing-the-world-as-an-argument thing, I guess.


_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Reply via email to