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