
Alistair,
Thanks for your message regarding the debate about monads and purity.
What do you think about these additions as a discussion of the issue?
Does this address everything you think is needed? Is there a clearer
way to explain it?
Thanks,
Jeff
In the section "No Way Out":
----------
The IO monad is a familiar example of a one-way monad in Haskell.
Because you can't escape from the IO monad, it is impossible to write a
function that does a computation in the IO monad but returns a
non-monadic value. Not only are functions of the type IO a -> a
impossible to create, but any function whose result type does not
contain the IO type constructor is guaranteed not to use the IO monad.
Other monads, such as List and Maybe, do allow values out of the monad.
So it is possible to write non-monadic functions that internally do
computations in those monads. The one-way nature of the IO monad also
has consequences when combining monads, a topic that is discussed in
part III.
----------
and a little farther down:
----------
Some people argue that using monads to introduce non-pure features into
Haskell disqualifies it from claiming to be a pure functional language.
This subtle question — not particularly relevant to the practical
programmer — is revisited in the context of the I/O monad later in the
tutorial.
----------
Later, in the section on the I/O monad:
----------
In Haskell, the top-level main function must have type IO (), so that
programs are typically structured at the top level as an
imperative-style sequence of I/O actions and calls to functional-style
code. Revisiting the debate about the purity of Haskell (in a functional
sense), it is important to note that the IO monad only simulates
imperative-style I/O. The functions exported from the IO module do not
perform I/O themselves. They return I/O actions, which describe an I/O
operation to be performed. The I/O actions are combined within the IO
monad (in a purely functional manner) to create more complex I/O
actions, resulting in the final I/O action that is the main value of the
program. The result of the Haskell compiler is an executable function
incorporating the main I/O action. Executing the program "applies" this
ultimate I/O action to the outside world to produce a new state of the
world. This occurs only once per execution of the program, and since the
state of the world changes for each execution, the issue of purity is
neatly side-stepped.
----------
--
Jeff Newbern

I have a program which creates textfiles out of other files. Since the program is runned from windows I output some text strings (Like "File created succefully") and I need to stop the program before it quits so that the user can read the line outputted to know what went on and then he can press ENTER to quit the program. I managed to do this fine if no error occurs but when a error occurs I am having problems. The code goes like that main :: IO() main =catch (do Do all the needed stuff here putStr "File created Successfully. Press RETURN to quit" dummy <- getLine --Halts the program so the user can read the above line) putStr "Exiting now..." --needed since I can't finish a do function with the "dummy<- getLine" line) (\_ -> do putStr "\nFile not found. Press RETURN (ENTER) to quit." dumb <- getLine putStr "\nExiting...") So when the program runs, if the input file is found the program writes successfull creation of file but if the file doesn't exist, after the user gives the input filename and press enter, the program creates a new line and Halts (Probably because of the getLine function) without writing out anything, then when the user press ENTER again it writes the line at the first putStr (File not...), then writes the next putStr line under it (Exiting...) and exits. I don't know why it doesn't wirte the first line, halts and then when user press enter it writes the second and quits. Can anybody help me as I am not very familiar with exception and catches. Another question I have is: Is there any other function rather than getLine that halts a program and continues when a user press any key (Instead of ENTER) and besides this is an ugly code since getLine wasn't made for that but I couldn't find anything else myself. Thank you in advance. Best Regards Alex

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Your problems might be due to buffering. Try setting the stdin and stdout to 'NoBuffering'. BTW, how are your exceptions getting thrown? Tom On Tue, 12 Aug 2003 05:20 pm, Alexandre Weffort Thenorio wrote:
I have a program which creates textfiles out of other files. Since the program is runned from windows I output some text strings (Like "File created succefully") and I need to stop the program before it quits so that the user can read the line outputted to know what went on and then he can press ENTER to quit the program.
I managed to do this fine if no error occurs but when a error occurs I am having problems.
The code goes like that
main :: IO() main =catch (do Do all the needed stuff here putStr "File created Successfully. Press RETURN to quit" dummy <- getLine --Halts the program so the user can read the above line) putStr "Exiting now..." --needed since I can't finish a do function with the "dummy<- getLine" line) (\_ -> do putStr "\nFile not found. Press RETURN (ENTER) to quit." dumb <- getLine putStr "\nExiting...")
So when the program runs, if the input file is found the program writes successfull creation of file but if the file doesn't exist, after the user gives the input filename and press enter, the program creates a new line and Halts (Probably because of the getLine function) without writing out anything, then when the user press ENTER again it writes the line at the first putStr (File not...), then writes the next putStr line under it (Exiting...) and exits. I don't know why it doesn't wirte the first line, halts and then when user press enter it writes the second and quits.
Can anybody help me as I am not very familiar with exception and catches.
Another question I have is: Is there any other function rather than getLine that halts a program and continues when a user press any key (Instead of ENTER) and besides this is an ugly code since getLine wasn't made for that but I couldn't find anything else myself.
Thank you in advance.
Best Regards
Alex
_______________________________________________ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.2 (GNU/Linux)
iD8DBQE/O6W1Yha8TWXIQwoRAi1DAKCti9nHfnh3oldHI438bdV+3OA29ACg1nK8 tpf9eANLv870A0xIPzNTsBU= =Sylz -----END PGP SIGNATURE-----

Jeff Newbern wrote (on Tue, 12 Aug 2003 at 17:20): (proposed revisions)
> In the section "No Way Out": > ---------- > The IO monad is a familiar example of a one-way monad in Haskell. > Because you can't escape from the IO monad, it is impossible to write a > function that does a computation in the IO monad but returns a > non-monadic value. I wouldn't say that, as it is inaccurate. Of course you can return a value of _some_ monadic type eg. (Maybe ...). > Not only are functions of the type IO a -> a > impossible to create, You can quite easily write a function of type IO (IO a) -> IO a, which is a special case of that type. > but any function whose result type does not > contain the IO type constructor is guaranteed not to use the IO monad. That's rather vague: what does it mean for a function to use a monad? > Other monads, such as List and Maybe, do allow values out of the monad. > So it is possible to write non-monadic functions that internally do > computations in those monads. The one-way nature of the IO monad also > has consequences when combining monads, a topic that is discussed in > part III. > ---------- In summary, I've only a vague idea of what you are trying to say. If you can't reformulate it more precisely, don't add the above stuff. > and a little farther down: > ---------- > Some people argue that using monads to introduce non-pure features into > Haskell disqualifies it from claiming to be a pure functional language. > This subtle question not particularly relevant to the practical > programmer is revisited in the context of the I/O monad later in the > tutorial. > ---------- That's fair enough. I don't think the question is so much subtle as religious, as we might expect from the terminology of "purity". > Later, in the section on the I/O monad: > ---------- > In Haskell, the top-level main function must have type IO (), so that > programs are typically structured at the top level as an > imperative-style sequence of I/O actions and calls to functional-style > code. Revisiting the debate about the purity of Haskell (in a functional > sense), it is important to note that the IO monad only simulates > imperative-style I/O. That (about simulation) seems weak. A simulation isn't a vague syntactic resemblance. > The functions exported from the IO module do not > perform I/O themselves. They return I/O actions, which describe an I/O > operation to be performed. The I/O actions are combined within the IO > monad (in a purely functional manner) to create more complex I/O > actions, resulting in the final I/O action that is the main value of the > program. The result of the Haskell compiler is an executable function > incorporating the main I/O action. Executing the program "applies" this > ultimate I/O action to the outside world to produce a new state of the > world. That seems to me the wrong thing to say. There is no application. Whether or not the word is put in quotes, it is something involving a function and an argument. An IO action is not a function. > This occurs only once per execution of the program, and since the > state of the world changes for each execution, the issue of purity is > neatly side-stepped. > ---------- By "the program", I think you mean the IO action. I think it is right to speak of the action as something that is executed. Execution may involve (side-effect free) calculation; but execution is something essentially different from calculation, not an impure form of it. I'm sorry to sound negative -- it's just that you invited criticism. Your pages seem generally of a very high quality to me. Sorry not to be more constructive too. Peter Hancock

Peter, Thank you for criticism. This is exactly the kind of feedback I need. The overall message I have taken from your post is that I need to be more precise to convey the correct information and avoid confusion (or worse, misinformation). I should have said that a function which performs a computation in the I/O monad must have IO as the outermost constructor in its return type. I think that is more precise (and correct :-). As for the later text concerning "application" of the top-level I/O action, I will need to think for a while to see how I can word this more clearly. If you (or anyone else) have ideas, I'd like to hear them. Thanks again, Jeff On Tue, 2003-08-12 at 18:24, Peter G. Hancock wrote:
Jeff Newbern wrote (on Tue, 12 Aug 2003 at 17:20): (proposed revisions)
> In the section "No Way Out": > ---------- > The IO monad is a familiar example of a one-way monad in Haskell. > Because you can't escape from the IO monad, it is impossible to write a > function that does a computation in the IO monad but returns a > non-monadic value.
I wouldn't say that, as it is inaccurate. Of course you can return a value of _some_ monadic type eg. (Maybe ...).
> Not only are functions of the type IO a -> a > impossible to create,
You can quite easily write a function of type IO (IO a) -> IO a, which is a special case of that type.
> but any function whose result type does not > contain the IO type constructor is guaranteed not to use the IO monad.
That's rather vague: what does it mean for a function to use a monad?
> Other monads, such as List and Maybe, do allow values out of the monad. > So it is possible to write non-monadic functions that internally do > computations in those monads. The one-way nature of the IO monad also > has consequences when combining monads, a topic that is discussed in > part III. > ----------
In summary, I've only a vague idea of what you are trying to say. If you can't reformulate it more precisely, don't add the above stuff.
> and a little farther down:
> ---------- > Some people argue that using monads to introduce non-pure features into > Haskell disqualifies it from claiming to be a pure functional language. > This subtle question not particularly relevant to the practical > programmer is revisited in the context of the I/O monad later in the > tutorial. > ----------
That's fair enough. I don't think the question is so much subtle as religious, as we might expect from the terminology of "purity".
> Later, in the section on the I/O monad: > ---------- > In Haskell, the top-level main function must have type IO (), so that > programs are typically structured at the top level as an > imperative-style sequence of I/O actions and calls to functional-style > code. Revisiting the debate about the purity of Haskell (in a functional > sense), it is important to note that the IO monad only simulates > imperative-style I/O.
That (about simulation) seems weak. A simulation isn't a vague syntactic resemblance.
> The functions exported from the IO module do not > perform I/O themselves. They return I/O actions, which describe an I/O > operation to be performed. The I/O actions are combined within the IO > monad (in a purely functional manner) to create more complex I/O > actions, resulting in the final I/O action that is the main value of the > program. The result of the Haskell compiler is an executable function > incorporating the main I/O action. Executing the program "applies" this > ultimate I/O action to the outside world to produce a new state of the > world.
That seems to me the wrong thing to say. There is no application. Whether or not the word is put in quotes, it is something involving a function and an argument. An IO action is not a function.
> This occurs only once per execution of the program, and since the > state of the world changes for each execution, the issue of purity is > neatly side-stepped. > ----------
By "the program", I think you mean the IO action. I think it is right to speak of the action as something that is executed. Execution may involve (side-effect free) calculation; but execution is something essentially different from calculation, not an impure form of it.
I'm sorry to sound negative -- it's just that you invited criticism. Your pages seem generally of a very high quality to me. Sorry not to be more constructive too.
Peter Hancock -- Jeff Newbern
Nomaware, Inc.

Peter G. Hancock wrote:
Jeff Newbern wrote (on Tue, 12 Aug 2003 at 17:20): ? > The functions exported from the IO module do not > perform I/O themselves. They return I/O actions, which describe an I/O > operation to be performed. The I/O actions are combined within the IO > monad (in a purely functional manner) to create more complex I/O > actions, resulting in the final I/O action that is the main value of the > program. The result of the Haskell compiler is an executable function > incorporating the main I/O action. Executing the program "applies" this > ultimate I/O action to the outside world to produce a new state of the > world.
That seems to me the wrong thing to say. There is no application. Whether or not the word is put in quotes, it is something involving a function and an argument. An IO action is not a function.
So then, in your view, what *is* an IO action? One conceptual model is that an IO action with type (IO a) denotes a function of type World -> (World,a). Given that model, "applying" an IO action to the external world seems like a perfectly reasonable account of executing such an action. -antony -- Antony Courtney Grad. Student, Dept. of Computer Science, Yale University antony@apocalypse.org http://www.apocalypse.org/pub/u/antony

On Tue, Aug 12, 2003 at 03:04:39PM -0400, Antony Courtney wrote:
So then, in your view, what *is* an IO action?
One conceptual model is that an IO action with type (IO a) denotes a function of type World -> (World,a).
But the IO monad is not a state monad, because other agents may change the state of the world while a Haskell program is running. It's more accurate to say that the program returns an action to be executed by the environment: data IO a = Return a | Invoke (SysCall (IO a)) data SysCall r = GetChar (Char -> r) | PutChar Char r | ... In addition to the usual arguments, the system call is given a return continuation to enter on completion. (This was the model of interactive I/O used by Moggi in "An Abstract View of Programming Languages", and is also used by Fudgets.) Of course the interpretation the environment places on GetChar, etc is outside of the functional world. That simple model omits exceptions. One way of adding them is data IO a = Return a | Error IOError | Invoke (SysCall (IO a)) (IOError -> IO a)

On Tuesday, 2003-08-12, 18:20, CEST, Jeff Newbern wrote:
[...]
In the section "No Way Out": ---------- The IO monad is a familiar example of a one-way monad in Haskell. Because you can't escape from the IO monad, it is impossible to write a function that does a computation in the IO monad but returns a non-monadic value. Not only are functions of the type IO a -> a impossible to create, but any function whose result type does not contain the IO type constructor is guaranteed not to use the IO monad. Other monads, such as List and Maybe, do allow values out of the monad. So it is possible to write non-monadic functions that internally do computations in those monads. The one-way nature of the IO monad also has consequences when combining monads, a topic that is discussed in part III.
This sounds rather vague to me. I don't like the formulation of a function doing a computation in the IO monad because execution of I/O actions is done separated from function application and evaluation (although interleaved with it because of lazy evaluation etc.). Tell me, if I'm pedantic. By the way, it *is* possible to create a function of type IO a -> a: f :: IO a -> a f = const undefined That's why in my last mail I spoke about *useful* functions which are implementable for State (but not for IO).
[...]
The functions exported from the IO module do not perform I/O themselves.
This is what I wanted to say above.
They return I/O actions, which describe an I/O operation to be performed. The I/O actions are combined within the IO monad (in a purely functional manner) to create more complex I/O actions, resulting in the final I/O action that is the main value of the program.
Very good!
The result of the Haskell compiler is an executable function incorporating the main I/O action. Executing the program "applies" this ultimate I/O action to the outside world to produce a new state of the world.
I wouldn't talk about functions and function applications here because what you mean are not Haskell functions and applications of them. You can think of an I/O action being a function conceptually and the execution of it being a function application but using these terms here will most likely confuse readers.
[...]
Wolfgang

On Tue, 12 Aug 2003 23:15:30 +0200
Wolfgang Jeltsch
On Tuesday, 2003-08-12, 18:20, CEST, Jeff Newbern wrote:
[...]
In the section "No Way Out": ---------- The IO monad is a familiar example of a one-way monad in Haskell. Because you can't escape from the IO monad, it is impossible to write a function that does a computation in the IO monad but returns a non-monadic value. Not only are functions of the type IO a -> a impossible to create, but any function whose result type does not contain the IO type constructor is guaranteed not to use the IO monad. Other monads, such as List and Maybe, do allow values out of the monad. So it is possible to write non-monadic functions that internally do computations in those monads. The one-way nature of the IO monad also has consequences when combining monads, a topic that is discussed in part III.
This sounds rather vague to me. I don't like the formulation of a function doing a computation in the IO monad because execution of I/O actions is done separated from function application and evaluation (although interleaved with it because of lazy evaluation etc.). Tell me, if I'm pedantic.
By the way, it *is* possible to create a function of type IO a -> a: f :: IO a -> a f = const undefined
or just, f = undefined. This -would- be being pedantic and confusing.
That's why in my last mail I spoke about *useful* functions which are implementable for State (but not for IO).
[...]
The functions exported from the IO module do not perform I/O themselves.
This is what I wanted to say above.
They return I/O actions, which describe an I/O operation to be performed. The I/O actions are combined within the IO monad (in a purely functional manner) to create more complex I/O actions, resulting in the final I/O action that is the main value of the program.
Very good!
The result of the Haskell compiler is an executable function incorporating the main I/O action. Executing the program "applies" this ultimate I/O action to the outside world to produce a new state of the world.
I wouldn't talk about functions and function applications here because what you mean are not Haskell functions and applications of them. You can think of an I/O action being a function conceptually and the execution of it being a function application but using these terms here will most likely confuse readers.
Perhaps it would simply be best to just come out and describe the IO monad as a state transformer for the world (i.e. World -> (a,World)). Then explain that a function IO a -> a would have to make up a World to work, and obviously that's not meaningfully possible. With this interpretation (which is used by at least GHC), it's obvious to see that the output of a Haskell compiler (i.e. main) is a function from the World to a new World. Unfortunately, this description relies on knowledge of the State monad, so it may be best left to the section dedicated to the IO monad. On a side issue, throughout the tutorial you use the word "computation" to describe monadic "functions", which happens to be the word I prefer; however, here you use IO "action" rather than "computation". There doesn't seem to be much of a reason to change terminology here. I'm comfortable with both terms, and don't think it would cause much trouble for a beginner, but it does seem arbitrary. This also makes me think that at some point (I don't think you do this, but I may just not remember) you may want to make explicit the dichotomy in terminology. I.e. a remark along the lines of "throughout this tutorial we we'll use the term computation for monadic values", you could then for the IO section state "IO computations are also called IO actions" if you change it, or "an IO action is just another name for IO computation" if you continue using IO action.
participants (8)
-
Alexandre Weffort Thenorio
-
Antony Courtney
-
Derek Elkins
-
hancock@spamcop.net
-
Jeff Newbern
-
Ross Paterson
-
Thomas L. Bevan
-
Wolfgang Jeltsch