
Excerpts from C.M.Brown's message of Sat Sep 06 12:43:08 +0200 2008:
Hi Nicolas,
I'm sorry, but I just don't get it. What are you trying to say? I think it would be clearer if we started to define what exactly a "side-effect" is (in any language) and work our definitions from there, because now I'm really confused.
OK, let's restrict the word side-effect to printing on the screen as the only
side-effect possible.
Some recalls:
- Yes the 'IO' monad allow the user to define side-effecting functions
- No the user cannot produce a side-effect in a pure language
- The 'main' *function* is a side-effecting function
- The runtime system consume 'main' and trigger it's effects
Example:
putStrLn is a side-effecting function expecting *2* arguments,
the first one is the string to print, and the second one is the world state.
So if you could give to arguments to putStrLn you could make a side-effect,
however you don't have a value of type RealWorld.
Is this clear?
In <
On Sat, 6 Sep 2008, Nicolas Pouillard wrote:
Excerpts from C.M.Brown's message of Sat Sep 06 12:04:10 +0200 2008:
On Sat, 6 Sep 2008, Nicolas Pouillard wrote:
Excerpts from C.M.Brown's message of Fri Sep 05 22:12:05 +0200 2008:
Can you give an example? I don't see how that can be done using Control.Monad.State(.Strict).State, unless invocations of put or modify are considered side effects.
Actually, yes, sorry; I do see your point. I guess it's just IO then.
Technically, even the IO monad is pure, that's just the runtime-system that consume your 'main' function that perform effects (and unsafeP...).
But, sure the IO monad does have side-effects? I'm confused as to how it could be pure. Could you explain?
That's an important point to grasp about the way we do effects in a pure language.
Once we've understood that point one tend to be a little less precise and consider IO as effect-full.
I consider IO to be effect-full anyway - I can't see how it isn't!
In fact one consider the IO monad to be effect-full because we don't have a runIO [1] function that is safe. So to be clear you go in the monad, but you can't go out of it. In other terms you can make 'IO t' values but you can't get values inside of it (without being yourself inside of it again).
For instance the State monad have a runState [2] function that allows you to go out the of the monad, or in other terms to get the value inside. So the State monad really is pure.
The ST monad is also pure and provides a pure running function runST [3]. What is interesting with the ST monad is that one don't choose the state type, moreover one cannot access it either (no get and put functions). Moreover by having this rank-2 type the runST function force the caller to give a 'ST s a' computation that does not mix the state parameter 's'.
Internally one can see 'ST' to be defined by something like that: type ST s a = s -> (s, a) So not far of the State monad.
The IO monad internally is defined as 'ST RealWorld a', what means that 'IO a' values are in fact RealWorld passing function.
An example:
What is the side-effect of reducing 'putStrLn "Hello"'?
Easy answer, there is no side-effect in a pure language.
More precise answer: "Hello" :: String putStrLn :: String -> IO () So: putStrLn "Hello" :: IO () If one imprecisely expand IO: putStrLn "Hello" :: RealWorld -> (RealWorld, ()) Thus an argument is still missing, so no effect
Is this clearer?
[1] hypothetical type: runIO :: IO a -> a [2] runState :: State s a -> s -> (a, s) [3] runST :: (forall s. ST s a) -> a
-- Nicolas Pouillard aka Ertai