
Hi all, I've finished a first draft of what I call "First steps in Haskell". It's intended to be the very first thing a new user sees when they decide to try out Haskell. http://www.haskell.org/hawiki/FirstSteps?action=show It's a bit longer than I'd like, but I don't inmediately see anything I can take out without losing something valuable (given the purpose of this document). Thoughts and comments? Cheers, Daniel. -- /\/`) http://oooauthors.org /\/_/ http://opendocumentfellowship.org /\/_/ \/_/ I am not over-weight, I am under-tall. /

hi daniel, the link about german (deutsch) haskel courses is in fact a link to a dutch (nederlands) page. For the rest it looks good! Peter
Hi all,
I've finished a first draft of what I call "First steps in Haskell". It's intended to be the very first thing a new user sees when they decide to try out Haskell.
http://www.haskell.org/hawiki/FirstSteps?action=show
It's a bit longer than I'd like, but I don't inmediately see anything I can take out without losing something valuable (given the purpose of this document).
Thoughts and comments?
Cheers, Daniel. -- /\/`) http://oooauthors.org /\/_/ http://opendocumentfellowship.org /\/_/ \/_/ I am not over-weight, I am under-tall. / _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

pkeeken@students.cs.uu.nl wrote:
hi daniel, the link about german (deutsch) haskel courses is in fact a link to a dutch (nederlands) page.
For the rest it looks good!
Thanks. Fixed. I removed the wrong link. Cheers, Daniel. -- /\/`) http://oooauthors.org /\/_/ http://opendocumentfellowship.org /\/_/ \/_/ I am not over-weight, I am under-tall. /

On 12/20/05, Daniel Carrera
Hi all,
I've finished a first draft of what I call "First steps in Haskell". It's intended to be the very first thing a new user sees when they decide to try out Haskell.
http://www.haskell.org/hawiki/FirstSteps?action=show
It's a bit longer than I'd like, but I don't inmediately see anything I can take out without losing something valuable (given the purpose of this document).
Thoughts and comments?
It looks very good. The length isn't a problem to me, if anything I'd be happy expanding a little. One thing I'd consider adding is something along the lines of a section: ------------------------------------------------------------------------------------ == So how do I write "Hello, world"? == Well, the first thing you need to understand that in a functional language like Haskell, this is a harder question than it seems. Most of the code you will write in Haskell is "purely functional", which means that it returns the same thing every time it is run, and has no side effects. Code with side effects is referred to as "imperative", and is carefully isolated from functional code in Haskell. To deal with the distinction between functional and imperative code, Haskell uses a construct called the "IO monad". It's not hard to understand - basically, it's just a way of "wrapping up" imperative code so that there's a clear boundary between it and functional code - but most tutorial presentations of Haskell start with functional code, and introduce the IO monad later. As a taster, though, here is "Hello, world" in Haskell: {{{ module Main where main :: IO () main = putStrLn "Hello, World!" }}} Put this in a file called hello.hs, and compile it with `ghc -make hello.hs -o hello`. You'll get an executable called hello (or hello.exe on Windows). Run it to see the output. There will be plenty more on writing standalone programs, IO, and other aspects of the IO monad, as you learn more about Haskell. ------------------------------------------------------------------------------------ The point is, people *will* want to write "hello, world", so don't put them off by making it seem "hard". Show them how, explain where they will find out more, and explain why things like this come naturally at a later stage when learning Haskell than they do with, say, C. Paul.

== So how do I write "Hello, world"? ==
Well, the first thing you need to understand that in a functional language like Haskell, this is a harder question than it seems. Most of the code you will write in Haskell is "purely functional", which means that it returns the same thing every time it is run, and has no side effects. Code with side effects is referred to as "imperative", and is carefully isolated from functional code in Haskell.
I believe this description is a bit misleading. Code written in the IO monad is purely functional just the same. Haskell knows no other code than purely functional one. In my humble opinion, it's unfortunate that many tutorials and introductionary texts leave the impression that monadic code would be something utterly different than "normal" Haskell code. I feel it intimidates the reader by making a monad appear like black magic, even though it's little more than syntactic sugar to describe implicit function arguments. If we'd have an opaque "World" type instead of the IO monad, 'putStrLn' would be: putStrLn :: String -> World -> World How is this function any different from any other function? So why should putStrLn :: String -> IO () be different from any other function? Peter

On 20 Dec 2005 19:52:31 +0100, Peter Simons
== So how do I write "Hello, world"? ==
Well, the first thing you need to understand that in a functional language like Haskell, this is a harder question than it seems. Most of the code you will write in Haskell is "purely functional", which means that it returns the same thing every time it is run, and has no side effects. Code with side effects is referred to as "imperative", and is carefully isolated from functional code in Haskell.
I believe this description is a bit misleading. Code written in the IO monad is purely functional just the same. Haskell knows no other code than purely functional one. In my humble opinion, it's unfortunate that many tutorials and introductionary texts leave the impression that monadic code would be something utterly different than "normal" Haskell code. I feel it intimidates the reader by making a monad appear like black magic, even though it's little more than syntactic sugar to describe implicit function arguments.
If we'd have an opaque "World" type instead of the IO monad, 'putStrLn' would be:
putStrLn :: String -> World -> World
How is this function any different from any other function? So why should
putStrLn :: String -> IO ()
be different from any other function?
It's sometimes beneficial to "lie" a bit when starting out. Perhaps say something like "this is a simplified view of things, for all the gory details see chapter 19". Monadic IO is pretty darn cool, sadly that means that many tutorial authors are tempted to spend pages upon pages explaining exactly why it's cool and how it works, but that is NOT what most people starting out with the language need to read. I'm still looking for a good *practical* tutorial that I could recommend to newcomers. IO, data types and QuickCheck in the very first chapter, I say! Real program examples from the get go, and go into the theory on why this has been hard in FP before Haskell (or Monadic IO rather) much much later, so as to not scare people away. /S -- Sebastian Sylvan +46(0)736-818655 UIN: 44640862

On Tue, 2005-12-20 at 20:07 +0100, Sebastian Sylvan wrote: . . .
I'm still looking for a good *practical* tutorial that I could recommend to newcomers. IO, data types and QuickCheck in the very first chapter, I say! Real program examples from the get go, and go into the theory on why this has been hard in FP before Haskell (or Monadic IO rather) much much later, so as to not scare people away.
I second this motion. I've been interested in Haskell for some time, experimented with it several years ago, and then moved on to other things. That first time around I saw no comprehensible discussions of monadic IO (for example, I thought that the fact that when you're in a monad you can't get out was characteristic of monads in general, not a peculiarity of IO). The state of available knowledge for beginners has clearly improved since I last looked. I applaud this discussion for making Haskell more accessible for the newbie. (Now, if someone would just explain how to get reliable performance information while jumping through only a bounded number of hoops ... :-) -- Bill Wood

On Tue, Dec 20, 2005 at 08:07:29PM +0100, Sebastian Sylvan wrote:
I'm still looking for a good *practical* tutorial that I could recommend to newcomers. IO, data types and QuickCheck in the very first chapter, I say! Real program examples from the get go, and go into the theory on why this has been hard in FP before Haskell (or Monadic IO rather) much much later, so as to not scare people away.
Indeed, I have been wanting to write something like this for a long time. perhaps using ginsu or (a simplified) jhc as a long running example throughout the tutorial. unfortunatly my prose is worse than my code. But I think such a tutorial (book?) describing how to write a real-world haskell program from scratch without glossing over details like IO would be a really great addition to the haskell bookshelf. John -- John Meacham - ⑆repetae.net⑆john⑈

On Tue, 20 Dec 2005, Sebastian Sylvan wrote:
Monadic IO is pretty darn cool, sadly that means that many tutorial authors are tempted to spend pages upon pages explaining exactly why it's cool and how it works, but that is NOT what most people starting out with the language need to read.
I'm still looking for a good *practical* tutorial that I could recommend to newcomers. IO, data types and QuickCheck in the very first chapter, I say! Real program examples from the get go, and go into the theory on why this has been hard in FP before Haskell (or Monadic IO rather) much much later, so as to not scare people away.
Starting with IO in Haskell is like starting LaTeX with rotating text and making it colorful. Indeed IO _is_ complicated regardless of whether it is modelled by Monads in Haskell or differently in other languages. Beginners should start with non-monadic functions in order to later avoid IO in their functions whereever possible. There are a lot of non-IO applications a beginner can start with, such as using Hugs or GHCi as a programmable calculator.

Henning Thielemann wrote:
Starting with IO in Haskell is like starting LaTeX with rotating text and making it colorful.
Not at all!
Indeed IO _is_ complicated regardless of whether it is modelled by Monads in Haskell or differently in other languages.
Rubbish! 10 PRINT "WHAT IS YOUR NAME?" 20 INPUT NAME IO isn't complicated in BASIC.
Beginners should start with non-monadic functions in order to later avoid IO in their functions whereever possible.
Whilst localising IO to a small part of the program is generally a good idea, beginners should not be scared off by the thought that IO in Haskell is so hard it has to be covered on page 94. This is not the case. It should be introduced on page 1. If people want Haskell to be treated as a practical language, not just something for doing academic teaching and research with, it should be taught as a practical language - which means that things like IO and space/time usage come to the forefront. -- Robin

On Wed, 21 Dec 2005, Robin Green wrote:
Henning Thielemann wrote:
Starting with IO in Haskell is like starting LaTeX with rotating text and making it colorful.
Not at all!
Indeed IO _is_ complicated regardless of whether it is modelled by Monads in Haskell or differently in other languages.
Rubbish!
10 PRINT "WHAT IS YOUR NAME?" 20 INPUT NAME
IO isn't complicated in BASIC. I agree. Not that it's *really* complicated in haskell, though. I think all a tutorial needs to do is explain "= means a definition, <- means the left side is the result of the right side" In order to show that x = getLine means that x is the function getLine while x <- getLine means that x is the result of getLine
Monads can come *way* later I think, but even then they're not difficult at all.
Beginners should start with non-monadic functions in order to later avoid IO in their functions whereever possible.
Whilst localising IO to a small part of the program is generally a good idea, beginners should not be scared off by the thought that IO in Haskell is so hard it has to be covered on page 94. This is not the case. It should be introduced on page 1.
If people want Haskell to be treated as a practical language, not just something for doing academic teaching and research with, it should be taught as a practical language - which means that things like IO and space/time usage come to the forefront.
I agree with this wholeheartedly. When I first started playing with Haskell, some of the tutorials made it look like it was very difficult to do anything practical with it because doing real input and output seemed like an "advanced topic".

On Wed, 21 Dec 2005, Creighton Hogg wrote:
I agree with this wholeheartedly. When I first started playing with Haskell, some of the tutorials made it look like it was very difficult to do anything practical with it because doing real input and output seemed like an "advanced topic".
The drawback is that I saw many Haskell programs implemented with IO read/write functions which could be easily implemented without IO, using laziness.

On Wed, 21 Dec 2005, Henning Thielemann wrote:
On Wed, 21 Dec 2005, Creighton Hogg wrote:
I agree with this wholeheartedly. When I first started playing with Haskell, some of the tutorials made it look like it was very difficult to do anything practical with it because doing real input and output seemed like an "advanced topic".
The drawback is that I saw many Haskell programs implemented with IO read/write functions which could be easily implemented without IO, using laziness.
Can you think of any examples of things like that? Given that I'm still learning how to take advantage of laziness it'd be pretty interesting.

On Wed, 21 Dec 2005, Creighton Hogg wrote:
On Wed, 21 Dec 2005, Henning Thielemann wrote:
The drawback is that I saw many Haskell programs implemented with IO read/write functions which could be easily implemented without IO, using laziness.
Can you think of any examples of things like that? Given that I'm still learning how to take advantage of laziness it'd be pretty interesting.
Some example for writing a text the IO oriented way: do putStrLn "bla" replicateM 5 (putStrLn "blub") putStrLn "end" whereas the lazy way is putStr (unlines (["bla"] ++ replicate 5 "blub" ++ ["end"])) You see that the construction of the text is separated from the output, but the effect is rather the same in both variants: The text is constructed simultaneously with output. You could also make the separation explicit: text :: String text = unlines (["bla"] ++ replicate 5 "blub" ++ ["end"]) main = putStr text

Some example for writing a text the IO oriented way: do putStrLn "bla" replicateM 5 (putStrLn "blub") putStrLn "end"
whereas the lazy way is putStr (unlines (["bla"] ++ replicate 5 "blub" ++ ["end"]))
Um, maybe it's just me, but I think the first program is far superior to the second one. The last thing you want your I/O code to be is lazy. You want the exact opposite: you want it to be as strict as possible. Not only does the second version waste a lot of CPU time and memory for pointlessly constructing a lazily evaluated list nobody ever needs, it will also explode into your face the moment you use that approach to write any non-trivial number of bytes. Peter

On Wed, Dec 21, 2005 at 07:35:28PM +0100, Peter Simons wrote:
Some example for writing a text the IO oriented way: do putStrLn "bla" replicateM 5 (putStrLn "blub") putStrLn "end"
whereas the lazy way is putStr (unlines (["bla"] ++ replicate 5 "blub" ++ ["end"]))
Um, maybe it's just me, but I think the first program is far superior to the second one. The last thing you want your I/O code to be is lazy. You want the exact opposite: you want it to be as strict as possible. Not only does the second version waste a lot of CPU time and memory for pointlessly constructing a lazily evaluated list nobody ever needs, it will also explode into your face the moment you use that approach to write any non-trivial number of bytes.
Isn't it just the usual elegance/efficiency trade-off? Personally, I would prefer the first version, unless it was not efficient enought. Actually this example is a bit too simple to show the benefits and problems of both approaches. Consider using a pretty printing library vs doing the same thing as a sequence of putStr's. Best regards Tomasz -- I am searching for a programmer who is good at least in some of [Haskell, ML, C++, Linux, FreeBSD, math] for work in Warsaw, Poland

On Wed, 21 Dec 2005, Peter Simons wrote:
Some example for writing a text the IO oriented way: do putStrLn "bla" replicateM 5 (putStrLn "blub") putStrLn "end"
whereas the lazy way is putStr (unlines (["bla"] ++ replicate 5 "blub" ++ ["end"]))
Um, maybe it's just me, but I think the first program is far superior to the second one. The last thing you want your I/O code to be is lazy. You want the exact opposite: you want it to be as strict as possible. Not only does the second version waste a lot of CPU time and memory for pointlessly constructing a lazily evaluated list nobody ever needs, it will also explode into your face the moment you use that approach to write any non-trivial number of bytes.
Surely the actual explosion comes about because PutStr forces the lot at once? If PutStr were to evaluate a character at a time, the laziness would be slow and spew a lot of garbage to collect but not hang on to as much space as you suggest. Not to say that the strict solution isn't still more efficient, of course. -- flippa@flippac.org The task of the academic is not to scale great intellectual mountains, but to flatten them.

On Wed, Dec 21, 2005 at 06:58:14PM +0000, Philippa Cowderoy wrote:
Surely the actual explosion comes about because PutStr forces the lot at once? If PutStr were to evaluate a character at a time, the laziness would be slow and spew a lot of garbage to collect but not hang on to as much space as you suggest.
Try running putStrLn (unlines (repeat "hello!")) You may be surprised ;-) Best regards Tomasz -- I am searching for a programmer who is good at least in some of [Haskell, ML, C++, Linux, FreeBSD, math] for work in Warsaw, Poland

On Wed, 21 Dec 2005, Tomasz Zielonka wrote:
On Wed, Dec 21, 2005 at 06:58:14PM +0000, Philippa Cowderoy wrote:
Surely the actual explosion comes about because PutStr forces the lot at once? If PutStr were to evaluate a character at a time, the laziness would be slow and spew a lot of garbage to collect but not hang on to as much space as you suggest.
Try running
putStrLn (unlines (repeat "hello!"))
You may be surprised ;-)
Or not ;-) But yes, I should've checked and my comments on how that'll behave stand. It would be nice to think something clever could happen regarding memory management as well, but I'm familiar enough with GCed systems by now to be somewhat wary of cleverness. -- flippa@flippac.org A problem that's all in your head is still a problem. Brain damage is but one form of mind damage.

On Wed, Dec 21, 2005 at 07:13:07PM +0000, Philippa Cowderoy wrote:
Try running
putStrLn (unlines (repeat "hello!"))
You may be surprised ;-)
Or not ;-) But yes, I should've checked and my comments on how that'll behave stand. It would be nice to think something clever could happen regarding memory management as well, but I'm familiar enough with GCed systems by now to be somewhat wary of cleverness.
I don't know how it's done, but when you compile it with 'ghc -O2', the program runs in constant space. Unfortunately with Hugs and GHCi it grows. Best regards Tomasz -- I am searching for a programmer who is good at least in some of [Haskell, ML, C++, Linux, FreeBSD, math] for work in Warsaw, Poland

On Wed, 21 Dec 2005, Tomasz Zielonka wrote:
I don't know how it's done, but when you compile it with 'ghc -O2', the program runs in constant space. Unfortunately with Hugs and GHCi it grows.
The live set, or just the heap? -- flippa@flippac.org A problem that's all in your head is still a problem. Brain damage is but one form of mind damage.

On Wed, Dec 21, 2005 at 09:30:14PM +0000, Philippa Cowderoy wrote:
On Wed, 21 Dec 2005, Tomasz Zielonka wrote:
I don't know how it's done, but when you compile it with 'ghc -O2', the program runs in constant space. Unfortunately with Hugs and GHCi it grows.
The live set, or just the heap?
It depends on what you mean by live set. If it's the conservative approximation as used by GC (reachability from root set), then yes, because it more or less equals heap. If you mean the set of nodes that will be referenced by program in the future, then probably no. You mean the latter, right? Best regards Tomasz -- I am searching for a programmer who is good at least in some of [Haskell, ML, C++, Linux, FreeBSD, math] for work in Warsaw, Poland

On 21/12/05, Tomasz Zielonka
On Wed, Dec 21, 2005 at 07:13:07PM +0000, Philippa Cowderoy wrote:
Try running
putStrLn (unlines (repeat "hello!"))
You may be surprised ;-)
Or not ;-) But yes, I should've checked and my comments on how that'll behave stand. It would be nice to think something clever could happen regarding memory management as well, but I'm familiar enough with GCed systems by now to be somewhat wary of cleverness.
I don't know how it's done, but when you compile it with 'ghc -O2', the program runs in constant space. Unfortunately with Hugs and GHCi it grows.
It really shouldn't grow at all, and at least in my short tests in ghci and hugs, it doesn't grow for me. The putStrLn won't force any more of the string than it wants to print at any moment, and afterward, that part of the string is garbage, and should get collected right away. There are two ways to make a Haskell program more efficient: Make it stricter, or make it lazier. What do I mean by the latter? Simply that if you can design each part of your program (as much as possible) to be able to output something only given a small prefix of its input, then you'll often see some really nice efficiency. The pipeline scheduler which I wrote for a summer job made heavy use of this fact, and at a few points in the design/coding, I made ridiculously large performance gains in both memory consumption and runtime simply by making sure that lists and other structures were lazily produced. In the end, the result was a (combinatorially large) list of all the possible schedules for the given input code, in order of algorithm greediness. Taking the head of the list was essentially running the greedy algorithm, but if the greedy solution, say, couldn't be register allocated, the next item in the list could be observed, which would backtrack a bit and find another. In fact, the entire algorithm was designed this way. That's essentially what the list monad gives you, after all. Leaning on laziness can result in very elegant generative algorithms which run quite quickly. Strictness is really only desired when you are trying to collapse something large down into a small summary. That's what things like foldl' are for. - Cale

Creighton Hogg wrote:
On Wed, 21 Dec 2005, Henning Thielemann wrote:
The drawback is that I saw many Haskell programs implemented with IO read/write functions which could be easily implemented without IO, using laziness.
Can you think of any examples of things like that? Given that I'm still learning how to take advantage of laziness it'd be pretty interesting.
Here's another one: I've heard a fellow claim, Haskell is basically unsuitable to implement a compiler, because Haskell is weak at IO and "everything needs IO, the lexer, the preprocessor, the parser, the pretty-printer, ..." Can you imagine what convoluted mess he would write if he learned IO first? Therefore I think, if, say, chapter 6 includes "A parser for Things is a function from Strings to a list of Things and Strings", then chapter 7 is the earliest that should include IO beyond getContents and putStr. The funny thing is, after the parser IO is simply another monad. At this point, the compiler becomes an imperative one-liner and lots of pure functions. Udo. -- I piss on you all from a considerable height. -- Louis Ferdinand Celine

On Wed, 21 Dec 2005, Udo Stenzel wrote: [... re pitfalls of IO for the beginner ]
Here's another one: I've heard a fellow claim, Haskell is basically unsuitable to implement a compiler, because Haskell is weak at IO and "everything needs IO, the lexer, the preprocessor, the parser, the pretty-printer, ..." Can you imagine what convoluted mess he would write if he learned IO first?
I wouldn't be too worried. If these things really must be learned in some prescribed order, then we're all doomed - who here learned Haskell as their first programming language? Meanwhile, that fellow evidently didn't write any compiler in Haskell at all. Better a C++ program than a Haskell program that offends you? Donn Cave, donn@drizzle.com

Donn Cave wrote:
Meanwhile, that fellow evidently didn't write any compiler in Haskell at all. Better a C++ program than a Haskell program that offends you?
Oh no, he actually wrote something disgusting built mostly out of regexes in Perl. I don't think it even works, and I don't think I could have convinced him to Do The Right Thing in whatever language. But that's besides the point. The conviction that a parser or lexer or prettyprinter means IO is simply wrong, and imho a tutorial should show how much is purely functionally possible before introducing control flow, mutable variables and all the other ugliness. It's more productive this way. Udo. -- Slous' Contention: If you do a job too well, you'll get stuck with it.

On Wednesday 21 December 2005 18:48, Udo Stenzel wrote:
Donn Cave wrote:
Meanwhile, that fellow evidently didn't write any compiler in Haskell at all. Better a C++ program than a Haskell program that offends you?
Oh no, he actually wrote something disgusting built mostly out of regexes in Perl. I don't think it even works, and I don't think I could have convinced him to Do The Right Thing in whatever language.
But that's besides the point. The conviction that a parser or lexer or prettyprinter means IO is simply wrong, and imho a tutorial should show how much is purely functionally possible before introducing control flow, mutable variables and all the other ugliness. It's more productive this way.
This is a red herring IMO. A good tutorial on Haskell can mention and explain how to do IO in the first chapter and /still/ show clearly and convincing how to do most of the real work in an elegant, purely functional style. It could even contain a 'bad example' where IO is used unnecessarily and compare it to the 'good' functional version. It is not a good idea to treat beginner's in Haskell as little children who must be protected from the bad world of IO as long as possible. (FWIW, it can be argued that this isn't even a good attitude toward little children.) Especially since most Haskell newcomers will have a background in imperative programming, as someone esle already mentioned. Of course, /precise/ explanation of the IO monad must be postponed to a later chapter, and surely only /after/ introducing monads in general and giving some non-IO examples. I would also argue that the word 'category theory' should /not/ appear in the main text of a tutorial (a small footnote might be acceptable, as well as a reference in a late chapter named 'further reading'). Ben

On Wed, 21 Dec 2005, Udo Stenzel wrote:
Donn Cave wrote:
Meanwhile, that fellow evidently didn't write any compiler in Haskell at all. Better a C++ program than a Haskell program that offends you?
But that's besides the point. The conviction that a parser or lexer or prettyprinter means IO is simply wrong, and imho a tutorial should show how much is purely functionally possible before introducing control flow, mutable variables and all the other ugliness. It's more productive this way.
Btw. Simon Thompson states in his book, that he found it didactically infelicitous to introduce recursion before higher order functions because that let beginners stick to case discriminations and recursive programming instead of taking advantage of functions like 'map', 'iterate', 'fold' etc. I can confirm this experience and I think that it is similar to IO vs. non-IO.

Robin Green wrote:
Whilst localising IO to a small part of the program is generally a good idea, beginners should not be scared off by the thought that IO in Haskell is so hard it has to be covered on page 94. This is not the case. It should be introduced on page 1.
As a newbie... I'll agree with Robin. I /did/ think that IO in Haskell was probably very difficult because it's covered in page 94. I skimmed through YAHT and IO is covered waaaayyy deep into the document. I haven't read that section yet, but there is a lot of content and to me it looked like it must be something difficult. I guess/hope that when I get around to reading it I'll find out that it's not as scary as it looks.
If people want Haskell to be treated as a practical language, not just something for doing academic teaching and research with, it should be taught as a practical language - which means that things like IO and space/time usage come to the forefront.
Until recently I thought of Haskell as something you would use for Calculus and the like. It seemed like a tool for academia. You may be interested to know that one of the reasons I started looking at Haskell just now was to help a friend understand Calculus (the other reason is that Haskell looks very cool). Cheers, Daniel. -- /\/`) http://oooauthors.org /\/_/ http://opendocumentfellowship.org /\/_/ \/_/ I am not over-weight, I am under-tall. /

On Wednesday 21 December 2005 12:17, Daniel Carrera wrote:
Robin Green wrote:
Whilst localising IO to a small part of the program is generally a good idea, beginners should not be scared off by the thought that IO in Haskell is so hard it has to be covered on page 94. This is not the case. It should be introduced on page 1.
As a newbie... I'll agree with Robin. I /did/ think that IO in Haskell was probably very difficult because it's covered in page 94. I skimmed through YAHT and IO is covered waaaayyy deep into the document. I haven't read that section yet, but there is a lot of content and to me it looked like it must be something difficult. I guess/hope that when I get around to reading it I'll find out that it's not as scary as it looks.
Rest assured it is dead simple. Really. I would even argue that it is a lot simpler than in many other languages. The only thing that is strange for beginners is that you cannot /do/ IO from inside a function (because functions in Haskell are pure, period). However you can easily /construct IO-performing actions/ inside functions, since such actions are ordinary (first-class) /data values/. That's what monadic IO is about. IO-actions (=procedures?) are data and can be manipulated like other ordinary data. However, since IO is necessarily an /abstract/ data type, data construction is limited to what's offered by the public interface (which is essentially the type class 'Monad', plus all the 'primitive' actions, i.e. putChar, getChar, openFile, ...). One of the funny aspects of IO in Haskell is that it tends to look like perfectly ordinary imperative programming. That is what the do-Notation (including <- 'assignment') is about. Ben

As a newbie... I'll agree with Robin. I /did/ think that IO in Haskell was probably very difficult because it's covered in page 94. I skimmed through YAHT and IO is covered waaaayyy deep into the document. I haven't read that section yet, but there is a lot of content and to me it looked like it must be something difficult. I guess/hope that when I get around to reading it I'll find out that it's not as scary as it looks.
Rest assured it is dead simple. Really. I would even argue that it is a lot simpler than in many other languages.
I agree. It's on page 31 in YAHT, and 1-11 are "getting started with Hugs" and so on. One of the whole points of YAHT is to introduce it early. -- Hal Daume III | hdaume@isi.edu "Arrest this man, he talks in maths." | www.isi.edu/~hdaume

Robin Green wrote:
If people want Haskell to be treated as a practical language, not just something for doing academic teaching and research with, it should be taught as a practical language - which means that things like IO and space/time usage come to the forefront.
Strange, I always thought predictable, understandable and above all correct code would be the primary goal, with small and quick code coming later. To write interactive Haskell code well, you have to understand higher order functions. So the IO monad has to come late in any tutorial. Before that, IO should be restricted to the EVA principle ("Eingabe, Verarbeitung, Ausgabe" == "Input, Processing, Output"). It was a good principle in the 60s, and it still is. Unless you want to teach people to program as they would do in Basic, that is. Udo. -- You can pick your friends and you can pick your nose, but you can't pick your friend's nose.

Udo Stenzel wrote:
Strange, I always thought predictable, understandable and above all correct code would be the primary goal, with small and quick code coming later.
Depends on what you mean by "quick" and "small". Do you mean that the program should execute fast and have a small memmory foot-print? If so, I agree. If what you mean is that the programmer should be able to finish the project quickly and it shouldn't have too many lines of code, then I think those features are important.
To write interactive Haskell code well, you have to understand higher order functions.
That's scary, that you need advanced knowledge just to do IO.
Unless you want to teach people to program as they would do in Basic, that is.
I don't know what you mean by that. Cheers, Daniel. -- /\/`) http://oooauthors.org /\/_/ http://opendocumentfellowship.org /\/_/ \/_/ I am not over-weight, I am under-tall. /

Daniel Carrera wrote:
Depends on what you mean by "quick" and "small". Do you mean that the program should execute fast and have a small memmory foot-print?
I was referring to Robin's mentioning space/time usage, so yes, that's what I meant.
To write interactive Haskell code well, you have to understand higher order functions.
That's scary, that you need advanced knowledge just to do IO.
Actually not. You need advanced knowledge to *avoid* doing IO. (If higher order functions like map, fold count as advanced.) A good, readable, maintainable Haskell program is almost completely pure and does very little IO. Of course you can write an IO-heavy program in the same style you'd use in C, but it would be exactly as ugly.
Unless you want to teach people to program as they would do in Basic, that is.
I don't know what you mean by that.
You will soon. Once you get used to composing functions instead of sequencing actions, you'll appreciate the difference. Udo. -- Disco is to music what Etch-A-Sketch is to art.

Udo Stenzel wrote:
Unless you want to teach people to program as they would do in Basic, that is.
I don't know what you mean by that.
You will soon. Once you get used to composing functions instead of sequencing actions, you'll appreciate the difference.
Ah. Yes, I do think I understand the difference (my math background is stronger than my programming background). Daniel. -- /\/`) http://oooauthors.org /\/_/ http://opendocumentfellowship.org /\/_/ \/_/ I am not over-weight, I am under-tall. /

Am Mittwoch, 21. Dezember 2005 13:31 schrieb Daniel Carrera:
Udo Stenzel wrote:
Strange, I always thought predictable, understandable and above all correct code would be the primary goal, with small and quick code coming later.
Depends on what you mean by "quick" and "small". Do you mean that the program should execute fast and have a small memmory foot-print? If so, I agree. If what you mean is that the programmer should be able to finish the project quickly and it shouldn't have too many lines of code, then I think those features are important.
I agree, and keeping the IO-part of your programmes small helps with that in my experience. And as Cale wrote, working from the pure core to the IO-coating is more fun (personal inclination, of course). But yes, people want to write interactive programmes soon, so I think "Chapter 2: Basic I/O" where putStr(Ln), print, getLine, getChar, maybe also readFile and writeFile/appendFile are introduced, do-notation and '<-' are explained is a good idea. However, a section about "Why a special IO-type", "more comprehensive explanations to come" and "how to use Hugs/ghci to develop and test your algorithms" should be definitely included. That's my tuppence, feel free to disagree.
To write interactive Haskell code well, you have to understand higher order functions.
That's scary, that you need advanced knowledge just to do IO.
Unless you want to teach people to program as they would do in Basic, that is.
I don't know what you mean by that.
Cheers, Daniel.
ditto! P.S.: In May, there was a 'Daniel Carrera' around, too. Isn't that a strange coincidence?

Daniel Fischer wrote:
P.S.: In May, there was a 'Daniel Carrera' around, too. Isn't that a strange coincidence?
That was myself, using a different email address. I didn't get too far with Haskell that time, but I remembered that I liked it, so I'm going back to it a bit now. But I'm still a newbie :) Notice that I was already familiar with a few, very basic concepts ("what is functional programming?") Cheers, Daniel. -- /\/`) http://oooauthors.org /\/_/ http://opendocumentfellowship.org /\/_/ \/_/ I am not over-weight, I am under-tall. /

On Wed, 2005-12-21 at 13:10 +0100, Udo Stenzel wrote: . . .
tutorial. Before that, IO should be restricted to the EVA principle ("Eingabe, Verarbeitung, Ausgabe" == "Input, Processing, Output"). It was a good principle in the 60s, and it still is. Unless you want to teach people to program as they would do in Basic, that is.
Don't forget that the pioneers of IPO (Input,Process,Output) quickly went to HIPO (Hierarchical IPO). My natural design style is top-down, functional decomposition, separation of concerns, all the good things. Many problems involve relatively complex mixtures of IO and processing, which I can capture fairly naturally with programs whose IO is distributed over various nodes low in a functional decomposition tree. It often feels like I'm turning a program inside-out to have the IO monad at the top with pure functional snippets called at various points in a "do" sequence. And if the only way to express my decomposition tree is with a tree of "imperative" code inside the IO monad, then I start to ask, "Why am I here? I can write this in Scheme or Ocaml". Since I'm a Haskell novice, I'm well aware that I may totally misunderstand the situation. However, I hadn't seen anything in tutorials that would lead me to think so. That said, one of the great effects of these recent threads is that they've alerted me to the fact that apparently the available tutorial information has expanded and been improved since last I looked. So I think I shall now go do some deep browsing; thanks for the links. -- Bill Wood PS: While looking over my post it occurred to me that the issue is at least as much methodological as it is linguistic. So I ask: Does Haskell stand far enough apart from other programming languages to warrant adapting standard methodological principles to it? Is there an identifiable "Haskell Way"? -- bw

Hello Bill, Wednesday, December 21, 2005, 6:38:33 PM, you wrote: BW> PS: While looking over my post it occurred to me that the issue is at BW> least as much methodological as it is linguistic. So I ask: Does BW> Haskell stand far enough apart from other programming languages to BW> warrant adapting standard methodological principles to it? Is there an BW> identifiable "Haskell Way"? as the man, who learned Haskell just year ago, and written large enough imperative program in Haskell (you can see it at http://freearc.narod.ru), i can answer both "yes" and "no". yes, Haskell really changes the way i program. no, it not diverges from the standard methodology - it forces to use it! :) any real program uses global variables, side-effects of functions, manually controlled sharing of data and so on. imagine programming in language which just don't support any provision for those tricks well, Haskell implementations de-facto supports such tricks, but they are considered as "bad programming style" and can lead to problems with optimized compilation, so you will aspire to avoid them as much as possible. you will need to decide beforehand for each function, whether it will have side effects or will be pure (although you of course may change your solution, whis will require to edit all functions which directly or indirectly call it, because function with side effects cannot be called inside pure function) you will need to learn programming techniques, which can be used in reliable way instead of forbidden unreliable ones - such as implicit parameters and using large structure to pass through the many levels of calls all data needed for these functions you will become an expert in organizing cycles via recursion ay least, you must try :) even if Haskell is not useful as real programming language, you at least will improve your programming style ;) -- Best regards, Bulat mailto:bulatz@HotPOP.com

On Wed, 21 Dec 2005, Robin Green wrote:
Henning Thielemann wrote:
Starting with IO in Haskell is like starting LaTeX with rotating text and making it colorful.
Not at all!
Indeed IO _is_ complicated regardless of whether it is modelled by Monads in Haskell or differently in other languages.
Rubbish!
10 PRINT "WHAT IS YOUR NAME?" 20 INPUT NAME
IO isn't complicated in BASIC.
IO is always complicated: It means sending messages, follow redirections, updating contents of windows, writing to disks etc. Nevertheless it may be easily accessible in some languages like BASIC. But it is important to separate IO from computations, also in languages where IO is easily accessible. Usually students start writing programs with much user interaction and it is hard to convince them of the advantages of programming interfaces. So I prefer starting a tutorial without IO, interaction in GHCi and Hugs should be enough for the beginning.

Henning Thielemann wrote:
IO is always complicated:
I have never once thought it was complicated. All I've ever needed are "print()" and "readLine()" and those shouldn't be complicated IMO. And I wouldn't want to wait for page 120 to learn how to do that. My programs are not going to be useful if they can't get user input or produce output. I don't want to wait for page 120 to write my first useful program.
So I prefer starting a tutorial without IO, interaction in GHCi and Hugs should be enough for the beginning.
GHCi and Hugs are enough for the /beginning/ yes, but that doesn't mean that IO should go on chapter 7. How about putting it in chapter 2? Cheers, Daniel -- /\/`) http://oooauthors.org /\/_/ http://opendocumentfellowship.org /\/_/ \/_/ I am not over-weight, I am under-tall. /

On 21/12/05, Daniel Carrera
Henning Thielemann wrote:
IO is always complicated:
I have never once thought it was complicated. All I've ever needed are "print()" and "readLine()" and those shouldn't be complicated IMO. And I wouldn't want to wait for page 120 to learn how to do that. My programs are not going to be useful if they can't get user input or produce output. I don't want to wait for page 120 to write my first useful program.
For this much, see my reply to your message in the other thread :) IO in Haskell isn't really so bad if you take it the right way. However, we do have these really nice interactive environments for evaluating expressions. When I write a real application, often the last thing I write is 'main'. It's more fun to start with the core of the algorithm that I want to implement, or problem I want to solve, and work my way outward to the user interface. So perhaps it's more natural for a Haskell tutorial to start there. As a Haskell programmer, it's where I'd start to write my program.
So I prefer starting a tutorial without IO, interaction in GHCi and Hugs should be enough for the beginning.
GHCi and Hugs are enough for the /beginning/ yes, but that doesn't mean that IO should go on chapter 7. How about putting it in chapter 2?
Cheers, Daniel -- /\/`) http://oooauthors.org /\/_/ http://opendocumentfellowship.org /\/_/ \/_/ I am not over-weight, I am under-tall. / _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

Interesting discussion ... I don't think it is necessary/desirable to relegate IO to `chapter 14'. First of all, IO is handled differently in Haskell as the language designers quite successfully resisted the temptation of impurity. However, you don't have to understand the full implications of IO to be able to use it (like you don't have to know the full English grammar to be able to speak English). I typically cover IO very early in a Haskell course and then again in `chapter 14' after a discussion of monads. (To motivate the need for a special treatment of IO, I often ask the students to put themselves into the position of a language designer who tries to add IO to a purely functional language.) So why is there a special `IO' type? The type serves to distinguish between values and effectful computations: `String' is the type of strings, `IO String' is the type of computations that deliver a string. This is why the `do' notation uses `<-' instead of `='.
ask :: String -> IO String ask question = do { putStrLn question; answer <- getLine; putStrLn "Thanks!"; return answer }
Here, `answer' of type `String' is the result of the effectful computation `getLine' of type `IO String'. I think IO can be treated on this level, just using the `do'-notation (it is not necessary to explain that the do-notations is merely syntactic sugar for `>>=' which involves higher-order functions). One thing that is important to stress, however, is that `<-' is a binder: the variable on the lhs is *bound* to value delivered by the rhs. In other words, `<-' introduces a variable (it does not assign a value to a store). Consequently, in do { a <- m1; a <- m2; ... } the second occurrence of `a' shadows the first occurrence. It is useful to think of `IO' as a `description' of an effectful computation (it is very much like a TODO list; the list describes actions, which may or may not be executed). This is why something of type `IO a' is also a value: it may be stored in a data structure or passed to a function. This means you can program you own control structures:
data IOTree a = Done (IO a) | Choice (IO Bool) (IOTree a) (IOTree a)
execute :: IOTree a -> IO a execute (Done action) = do { action } execute (Choice action left right) = do { b <- action; if b then do { execute left } else do { execute right } }
Now, if IO is only a `description' of an IO action, when is the IO action actually executed? Exactly when `main' is called: only the TODO list that is bound to `main' is executed. Consider
main = do { head [putStrLn "hello world", putStrLn "too lazy"] }
HTH, Ralf

Am Mittwoch, 21. Dezember 2005 11:48 schrieb Robin Green:
[...]
If people want Haskell to be treated as a practical language, not just something for doing academic teaching and research with, it should be taught as a practical language - which means that things like IO and space/time usage come to the forefront.
So programming is only practical if it's deals with a lot of I/O? This is wrong, in my opinion. Take a compiler. The only I/O it does is some simple file I/O. The important part of the compiler doesn't deal with I/O at all. Best wishes, Wolfgang

Wolfgang Jeltsch wrote:
If people want Haskell to be treated as a practical language, not just something for doing academic teaching and research with, it should be taught as a practical language - which means that things like IO and space/time usage come to the forefront.
So programming is only practical if it's deals with a lot of I/O?
No, that's not what I meant at all. I meant that for *many* but not all practical programming tasks, IO is important. Games, GUI office applications, database applications, web applications, etc. Compilers are atypical in this regard. Something that is perceived as being only useful for a compilers and a few other academic-ish things isn't going to be perceived as very practically useful. -- Robin

Robin Green wrote:
I meant that for *many* but not all practical programming tasks, IO is important. ...web applications...
Ha, wrong! A CGI script only needs getEnv, getContents and putStr, if it has persistent state, it also needs readFile and writeFile. Each of the five is called exactly once per invocation. The main function is boiler plate, the bulk of the logic is pure. Same for a web application server, only less IO.
Compilers are atypical in this regard.
You wouldn't believe what diverse applications could be summed up under "compilers". Udo. -- If I ever write a GUI library for Haskell, I'm going to call it pointlesstif. -- Pseudonym on #haskell

On 12/21/05, Wolfgang Jeltsch
Am Mittwoch, 21. Dezember 2005 11:48 schrieb Robin Green:
[...]
If people want Haskell to be treated as a practical language, not just something for doing academic teaching and research with, it should be taught as a practical language - which means that things like IO and space/time usage come to the forefront.
So programming is only practical if it's deals with a lot of I/O? This is wrong, in my opinion. Take a compiler. The only I/O it does is some simple file I/O. The important part of the compiler doesn't deal with I/O at all.
I'm pretty sure that's not what he was saying. But a practical application need IO. I'm not saying that only applications doing *lots* of IO should be considered practical, I'm saying that any real-world stand-alone application needs *some* IO. Beginners know that too. In fact, they often think that practical applications need far more IO than they really do! So to insinuate even slightly that Haskell is "bad at IO" by avoiding it for two thirds of a book, is really going to inforce the idea that Haskell isn't a practical language for practical applications. It's easily remedied by teaching them a little IO up front (to show them it's not scary), and then leaving it alone for a while, having a more thorugough treatment of it later on. /S -- Sebastian Sylvan +46(0)736-818655 UIN: 44640862

Sebastian Sylvan wrote:
Beginners know that too. In fact, they often think that practical applications need far more IO than they really do! So to insinuate even slightly that Haskell is "bad at IO" by avoiding it for two thirds of a book, is really going to inforce the idea that Haskell isn't a practical language for practical applications. It's easily remedied by teaching them a little IO up front (to show them it's not scary), and then leaving it alone for a while, having a more thorugough treatment of it later on.
You can show them this on the first page: main = do x <- getLine() print my_program(x) And spend the next 200 pages showing them all the nifty things and purely functional things that my_program() could do and not mention monads until chapter 14. Cheers, Daniel. -- /\/`) http://oooauthors.org /\/_/ http://opendocumentfellowship.org /\/_/ \/_/ I am not over-weight, I am under-tall. /

On 12/21/05, Daniel Carrera
Sebastian Sylvan wrote:
Beginners know that too. In fact, they often think that practical applications need far more IO than they really do! So to insinuate even slightly that Haskell is "bad at IO" by avoiding it for two thirds of a book, is really going to inforce the idea that Haskell isn't a practical language for practical applications. It's easily remedied by teaching them a little IO up front (to show them it's not scary), and then leaving it alone for a while, having a more thorugough treatment of it later on.
You can show them this on the first page:
main = do x <- getLine() print my_program(x)
Well, more like main = do x <- getLine print (my_program x) But we get the point! :-) -- Sebastian Sylvan +46(0)736-818655 UIN: 44640862

On Wednesday 21 December 2005 16:49, Sebastian Sylvan wrote:
On 12/21/05, Daniel Carrera
wrote: Sebastian Sylvan wrote:
Beginners know that too. In fact, they often think that practical applications need far more IO than they really do! So to insinuate even slightly that Haskell is "bad at IO" by avoiding it for two thirds of a book, is really going to inforce the idea that Haskell isn't a practical language for practical applications. It's easily remedied by teaching them a little IO up front (to show them it's not scary), and then leaving it alone for a while, having a more thorugough treatment of it later on.
You can show them this on the first page:
main = do x <- getLine() print my_program(x)
Well, more like
main = do x <- getLine print (my_program x)
This: main = do x <- getLine print (my_program x) would be correct too. (Just to make it clear that the main point was not the different layout but the parentheses: Haskell uses them only to indicate precedence, they are not required around function arguments.) Ben

Hello Daniel, Wednesday, December 21, 2005, 6:34:10 PM, you wrote: DC> You can show them this on the first page: DC> main = do DC> x <- getLine() DC> print my_program(x) this named `interactive` :) try: main = interactive(map toUpper) -- Best regards, Bulat mailto:bulatz@HotPOP.com

<noise> The truth is, Haskell friggen rocks at IO compared to imperative languages. We are all spoiled and see IO in haskell as ugly because we have been exposed to the pure functional goodness of the rest of haskell. but teaching haskell as a better impertive language than imperative ones from the getgo seems like a very good approach for bringing people over. Just the idea that you can write things like mapM and replicateM is enough to blow the mind of many impertive programmers. They don't need to be forced to learn the pure functional side, they will eventually learn to do so on their own because it is so darn nice. You can't not start with IO for people who already know how to program, if you are teaching someone programming for the very first time then starting with the pure functional side is fine. But for people that already know how to program, they are constantly thinking of everything else they have written and how they might do it in the language they are currently learning comparing and contrasting in their head. They need to have the tools to replicate what they have done with other languages right away, they don't want to know how to do the examples given in the book except insofar as they let them understand how to write the examples wiggling around in their head. </noise> John -- John Meacham - ⑆repetae.net⑆john⑈

On 12/22/05, John Meacham
Just the idea that you can write things like mapM and replicateM is enough to blow the mind of many impertive programmers.
Not trying to fan the flames, but one thing I struggle with is understanding (at a "gut level" - if you explain the theory, I'll understand, but go away none the wiser in practice...) why I need mapM as well as map (and all the other -M functions, liftM, foldM, etc...) mapM and so on really *are* why the IO monad is a great feature of Haskell. But the mental gearchange needed to appreciate what just happened is one of the speedbumps on the learning curve. You thought you were getting along fine, you'd got the point of functional stuff like map and fold, and you understood IO and it wasn't as scary as you'd thought. But then along comes mapM, and you're struggling again - why not just use map? And the explanation doesn't help much, it just leaves you feeling that you'd missed the point. As I say, I'm not trying to criticize anyone here, but it seems to be quite hard to get across to people who have understood and assimilated this sort of stuff, just how hard it feels to newcomers. We understand the explanations (we do! really! :-)) but even understanding them, we are still left with a lack of confidence. It's like being shown a full set of carpentry tools, having every one explained, but still reaching for the hammer every time and banging something no matter what we're trying to do :-) Paul.

Paul Moore wrote:
As I say, I'm not trying to criticize anyone here, but it seems to be quite hard to get across to people who have understood and assimilated this sort of stuff, just how hard it feels to newcomers. We understand the explanations (we do! really! :-)) but even understanding them, we are still left with a lack of confidence. It's like being shown a full set of carpentry tools, having every one explained, but still reaching for the hammer every time and banging something no matter what we're trying to do :-)
I had never heard of mapM, or other -M functions. I can't imagine why those would be needed. It seems like pointless duplication. Daniel. -- /\/`) http://oooauthors.org /\/_/ http://opendocumentfellowship.org /\/_/ \/_/ I am not over-weight, I am under-tall. /

On 12/22/05, Daniel Carrera
Paul Moore wrote:
As I say, I'm not trying to criticize anyone here, but it seems to be quite hard to get across to people who have understood and assimilated this sort of stuff, just how hard it feels to newcomers. We understand the explanations (we do! really! :-)) but even understanding them, we are still left with a lack of confidence. It's like being shown a full set of carpentry tools, having every one explained, but still reaching for the hammer every time and banging something no matter what we're trying to do :-)
I had never heard of mapM, or other -M functions. I can't imagine why those would be needed. It seems like pointless duplication.
Thanks for confirming my point! FWIW, I don't really see why the -M functions are needed either. It's something to do with the fact that map is for lists, and mapM is for monads, which are a more general type of sequence than a list. But why mapM isn't therefore a superset of map, and so map is redundant, I don't know. (For experts who might want to explain, please note that I can look the differences up. But I can't *picture* the differences well enough to remember them, and hence not *need* to look them up every time, nor can I internalise the differences well enough to use the 2 forms in the correct contexts). Paul.

On Thu, 22 Dec 2005, Paul Moore wrote: ...
FWIW, I don't really see why the -M functions are needed either. It's something to do with the fact that map is for lists, and mapM is for monads, which are a more general type of sequence than a list. But why mapM isn't therefore a superset of map, and so map is redundant, I don't know.
This reminds me why I like Hugs - whether I normally use it or not, I have it installed so that I can refer to lib/Prelude.hs, my single most useful Haskell document. You can offer any number of conceptual explanations of these things, but there seems to be no way to guarantee that they're going to be taken the right way. The Prelude definitions may or may not make sense, but at worst I don't think they can muddy the issue. I'm also reminded that there we're talking about several distinctly different types of learning here. If you're taking a class, you might well profit from a structured sequence that focuses on the static declarative aspects first, avoids recursion, etc. If you're on your own - as commonly the case with people reading tutorials - it's important to present the language in a useful form as soon as possible, let there be a temptation to switch to the Objective CAML tutorial because of a mistaken impression. Donn Cave, donn@drizzle.com ------- sequence :: Monad m => [m a] -> m [a] sequence [] = return [] sequence (c:cs) = do x <- c xs <- sequence cs return (x:xs) sequence_ :: Monad m => [m a] -> m () sequence_ = foldr (>>) (return ()) mapM :: Monad m => (a -> m b) -> [a] -> m [b] mapM f = sequence . map f mapM_ :: Monad m => (a -> m b) -> [a] -> m () mapM_ f = sequence_ . map f

On Thu, Dec 22, 2005 at 02:02:56PM +0000, Daniel Carrera wrote:
Paul Moore wrote:
As I say, I'm not trying to criticize anyone here, but it seems to be quite hard to get across to people who have understood and assimilated this sort of stuff, just how hard it feels to newcomers. We understand the explanations (we do! really! :-)) but even understanding them, we are still left with a lack of confidence. It's like being shown a full set of carpentry tools, having every one explained, but still reaching for the hammer every time and banging something no matter what we're trying to do :-)
I had never heard of mapM, or other -M functions. I can't imagine why those would be needed. It seems like pointless duplication.
The point of mapM is that you can use side-effects for each element processed. For example, with mapM in IO monad you can turn a list of filenames into a list of file contents. Actually, it is map that is redundant, because it's equivalent to mapM for the Identity monad. Best regards Tomasz -- I am searching for a programmer who is good at least in some of [Haskell, ML, C++, Linux, FreeBSD, math] for work in Warsaw, Poland

On Thu, Dec 22, 2005 at 02:02:56PM +0000, Daniel Carrera wrote:
I had never heard of mapM, or other -M functions. I can't imagine why those would be needed. It seems like pointless duplication.
(!!!) then you are missing out. the M functions (and monadic traversal functions in general) especially when combined with the mtl are some of the best swiss army knives haskell has to offer. and it is map that is redundant. map f xs = runIdentity $ mapM f xs sequence = mapM id I have come to think of the monadic forms of these functions as the 'true' versions and the others as just common special cases. though, not my most common function used from the prelude, it is up there. and the most commonly used non-trivial function other than return: 922 mapM 937 Nothing 1017 not 1061 error 1433 String 1456 Just 1544 IO 1777 map 1810 show 1972 text 2595 Int 5303 return John -- John Meacham - ⑆repetae.net⑆john⑈

SKC> This entire discussion is about 'breaking a cyclic graph of conceptual SKC> dependencies'. Unfortunately, I don't think it can be done well in short SKC> amount of time. I bet if we sat down and listed all the concepts required to write idiomatic Haskell (even idiomatic Haskell 98 (whatever this means)), to write programs that do the things that we all have done in other languages (you know what I'm talking about here, but of course this is up for debate too), we would see that it was not a linear structure but a cyclic graph or at best a tree of concepts: we need to understand higher order functions, polymorphic higher order types for monads, monads to understand I/O really well (or to understand WHY I/O in a purely functional language is the way it is), typeclasses, laziness, etc. etc. In a lot of situations, pedagogy is hard to 'linearize'. Why would it be any different in programming? especially in Haskell? A lot of learning Haskell is just helping reinforce this strong, but sometimes subtle "base of knowledge" required to really start to "get" Haskell. [1] HT> Btw. Simon Thompson states in his book, that he found it didactically HT> infelicitous to introduce recursion before higher order functions because HT> that let beginners stick to case discriminations and recursive programming HT> instead of taking advantage of functions like 'map', 'iterate', 'fold' HT> etc. I can confirm this experience and I think that it is similar to IO HT> vs. non-IO. It very well may be "didactically infelicitous" [2]. (I wish there were some program we can just run on a course syllabus and find out that something is "felicitous"):
conceptsInHaskell :: [haskellConcept] conceptsInHaskell = [...] -- abstract main = print $ sort conceptsInHaskell .. error: haskellConcept not a member of class Ord.
Maybe we'll (collectively) get better and better at this. I think we are. Hopefully experience and sharing this information will be beneficial to all (as well as discussion like these). Maybe it depends on who is learning Haskell, and why: maybe the 'conflict' is that "learning to program *in* Haskell" /= "learning to program *with* Haskell." But maybe it's not ultimately an optimizable piece of data, the "right" order of teaching concepts in Haskell. Maybe it should be allowed to be more random-access? (I personally like things more that way :-) . Cheers Jared. -- jupdike@gmail.com http://www.updike.org/~jared/ reverse ")-:" [1] Perhaps a point in Haskell's favor for pedagogy is that there are things you can do in Haskell that you just can't do (in the same, succint sense) in most programming languages, e.g. even OCaml. Maybe these things (and they are neat, simple things, like the code ""twos = 2:twos"" and then manipulating this infinite stream) can help motivate people to really want to grok Haskell, and to stick with it and use it for practical projects because of its many advantages. :-) [2] Paul Hudak does this in the Haskell School of Expression. He writes recursive code with cases, etc. and then in a later chapter explains how to rewrite it with map, fold, etc. Fine. It takes steps to learn how to write idiomatic Haskell. At least for me, the joy of Haskell is not in "memorizing vocabulary" (as is common in a language like Java, or C#) but rather, internalizing concepts. By writing ugly code at first and then seeing the patterns and refactoring with map and fold, I've personally internalized it (instead of learning some clever rule, up front, that I'll later forget). Think Why FP Matters by Hughes. He does this too (recursion, pattern matching, then later swapping in higher order functions), to explain why FP is so great.

On 12/22/05, Daniel Carrera
Paul Moore wrote:
As I say, I'm not trying to criticize anyone here, but it seems to be quite hard to get across to people who have understood and assimilated this sort of stuff, just how hard it feels to newcomers. We understand the explanations (we do! really! :-)) but even understanding them, we are still left with a lack of confidence. It's like being shown a full set of carpentry tools, having every one explained, but still reaching for the hammer every time and banging something no matter what we're trying to do :-)
I had never heard of mapM, or other -M functions. I can't imagine why those would be needed. It seems like pointless duplication.
mapM is like map except you map an IO Action over a list instead of a function of a list. For instance sizes <- mapM getFileSize myListOfFileNames If you used "map" here you'd end up with a list of IO actions, and not a list of file sizes. You'd then have to go through this list of IO actions and using (<-) on each element to get the file sizes. This can, incidentally, be done using the function 'sequence'. liftM lifts a function so that you can use a regular function on an IO Action instead of first having to extract the value of the IO action using (<-). It's just shorthand, so you could do: x <- liftM length (readFile "afile") Instead of having to do f <- readFile "afile" let x = length f The M functions really are useful, get to know them! /S -- Sebastian Sylvan +46(0)736-818655 UIN: 44640862

Paul Moore wrote:
Not trying to fan the flames, but one thing I struggle with is understanding (at a "gut level" - if you explain the theory, I'll understand, but go away none the wiser in practice...) why I need mapM as well as map (and all the other -M functions, liftM, foldM, etc...)
All you really need to understand is what sequence :: Monad m => [m a] -> m [a] does. Once you get that, the difference between map and mapM is clear because of mapM f xs = sequence (map f xs) Udo. -- Worrying is like rocking in a rocking chair -- It gives you something to do, but it doesn't get you anywhere.

Hello John, Thursday, December 22, 2005, 3:48:37 AM, you wrote: JM> You can't not start with IO for people who already know how to program, JM> if you are teaching someone programming for the very first time then JM> starting with the pure functional side is fine. But for people that JM> already know how to program, they are constantly thinking of everything JM> else they have written and how they might do it in the language they are JM> currently learning comparing and contrasting in their head. They need to JM> have the tools to replicate what they have done with other languages JM> right away, they don't want to know how to do the examples given in the JM> book except insofar as they let them understand how to write the JM> examples wiggling around in their head. yes, it's just about me :) first i time i tried to learn Haskell (afair, it was advertized on bzip2 page), i decided that it need to write everything as a pure function and found monad concept very complex (afair, "gentle introduction" emphasizes that monads are very complex things!). next time i tried to learn Haskell, my main question was "is it possible to use imperative style of controlling program action?". i recognized functional power of language and it was the last barrier to really use it so, i think, it is needed to "reassure" imperative programmers at first pages by demonstrating techiques of imperative programming, including conditional execution and IORef/MArray and only after that present more convenient alternatives. at least for my imperative feel, conditional execution, cycles, modifiable variables and arrays together form enough basis to implement any algorithm -- Best regards, Bulat mailto:bulatz@HotPOP.com

On Fri, 23 Dec 2005, Bulat Ziganshin wrote: ...
so, i think, it is needed to "reassure" imperative programmers at first pages by demonstrating techiques of imperative programming, including conditional execution and IORef/MArray and only after that present more convenient alternatives. at least for my imperative feel, conditional execution, cycles, modifiable variables and arrays together form enough basis to implement any algorithm
It's weird how many different perspectives there are on what's basic Haskell. Someone asks about mapM, and everyone agrees about that - it's definitely on the short list of things we want to know - but then we go on to liftM, which I've always thought was kind of a gratuitous extra way to spell >>=. We get to IO, and of course everyone agrees that it's on the short list (even if we differ on when to get to it), but -- IORef? Can't tell if you're serious. Donn Cave, donn@drizzle.com

Hello Donn, Friday, December 23, 2005, 8:30:34 PM, you wrote:
so, i think, it is needed to "reassure" imperative programmers at first pages by demonstrating techiques of imperative programming, including conditional execution and IORef/MArray and only after that present more convenient alternatives. at least for my imperative feel, conditional execution, cycles, modifiable variables and arrays together form enough basis to implement any algorithm
DC> We get to IO, and of course everyone agrees that it's on the short DC> list (even if we differ on when to get to it), but -- IORef? Can't DC> tell if you're serious. yes, i know that this viewpoint is extreme. but i said not about my current thoughts, but about my history of "buying" Haskell. i first found it in 2003, mastered all the "gentle introduction" except for monads and rejected. the second try in 2004 was more successfull. so i will repeat my point - i as imperative programmer need to "feel basis" and to know that in worst case i can write imperatively parts of program which don't fit in pure style. this not requires full explanation, just mentioning and may be examples (although these examples will sjow weakness of imperative Haskell facilities) -- Best regards, Bulat mailto:bulatz@HotPOP.com

Am Dienstag, 20. Dezember 2005 20:07 schrieb Sebastian Sylvan:
[...]
It's sometimes beneficial to "lie" a bit when starting out. Perhaps say something like "this is a simplified view of things, for all the gory details see chapter 19".
Monadic IO is pretty darn cool, sadly that means that many tutorial authors are tempted to spend pages upon pages explaining exactly why it's cool and how it works, but that is NOT what most people starting out with the language need to read.
I'm still looking for a good *practical* tutorial that I could recommend to newcomers. IO, data types and QuickCheck in the very first chapter, I say! Real program examples from the get go, and go into the theory on why this has been hard in FP before Haskell (or Monadic IO rather) much much later, so as to not scare people away.
I think that there are cases where it's better to start with ordinary functional programming and come to I/O later. In my opinion, an example case would be teaching Haskell at a university.
/S
/W

On 12/21/05, Wolfgang Jeltsch
Am Dienstag, 20. Dezember 2005 20:07 schrieb Sebastian Sylvan:
[...]
It's sometimes beneficial to "lie" a bit when starting out. Perhaps say something like "this is a simplified view of things, for all the gory details see chapter 19".
Monadic IO is pretty darn cool, sadly that means that many tutorial authors are tempted to spend pages upon pages explaining exactly why it's cool and how it works, but that is NOT what most people starting out with the language need to read.
I'm still looking for a good *practical* tutorial that I could recommend to newcomers. IO, data types and QuickCheck in the very first chapter, I say! Real program examples from the get go, and go into the theory on why this has been hard in FP before Haskell (or Monadic IO rather) much much later, so as to not scare people away.
I think that there are cases where it's better to start with ordinary functional programming and come to I/O later. In my opinion, an example case would be teaching Haskell at a university.
Well, I certainly disagree there. I'm not advocating going into a full-blown explanation of monads, just enough to actually be able to write a real stand-alone program after the first chapter. They only need to know that do-notation is for sequencing computations, and (<-) is for binding a name to the result of a computation. That's it! You could spend the next ten chapters with coding examples that are not very IO-heavy, and lead with a good example of doing as much as possible in the pure world (as well as pointing out every now and then whenever a particularly good "IO-separtion" was achieved - to emphasize that it's good practice). When someone who has programmed before learns Haskell and gets the impression that IO is beeing left for later because it's "hard" they might think "bah, what a rubbish language, IO in Visual Basic isn't hard at all!". /S -- Sebastian Sylvan +46(0)736-818655 UIN: 44640862

Sebastian Sylvan wrote:
Well, I certainly disagree there. I'm not advocating going into a full-blown explanation of monads, just enough to actually be able to write a real stand-alone program after the first chapter. They only need to know that do-notation is for sequencing computations, and (<-) is for binding a name to the result of a computation. That's it!
As a newbie... I agree that a newbie should be able to write this fairly early on: main = do x <- getLine() putStrLn ("The answer is " ++ show(fib(read(x)))) Now, you just said "do-notation is for sequencing computations". Would it be fair to say that do-blocks are imperative blocks in an otherwise functional program?
You could spend the next ten chapters with coding examples that are not very IO-heavy, and lead with a good example of doing as much as possible in the pure world (as well as pointing out every now and then whenever a particularly good "IO-separtion" was achieved - to emphasize that it's good practice).
When someone who has programmed before learns Haskell and gets the impression that IO is beeing left for later because it's "hard" they might think "bah, what a rubbish language, IO in Visual Basic isn't hard at all!".
I would agree with both paragraphs. Show basic IO and show that there's no need for complex IO because all the logic should be functional. Cheers, Daniel. -- /\/`) http://oooauthors.org /\/_/ http://opendocumentfellowship.org /\/_/ \/_/ I am not over-weight, I am under-tall. /

Am Mittwoch, 21. Dezember 2005 16:30 schrieb Daniel Carrera:
[...]
Would it be fair to say that do-blocks are imperative blocks in an otherwise functional program?
Not really. do expressions are (normally) equivalent to expressions containing applications of (>>=) and/or (>>). If the monad you use is IO then a do expression isn't really an imperative block but an expression whose value is a *description* of an imperative block. If the monad you use is not IO then a do expression may have nothing to do with imperative code at all.
[...]
Cheers, Daniel.
Best wishes, Wolfgang

Daniel Carrera wrote:
As a newbie... I agree that a newbie should be able to write this fairly early on:
main = do x <- getLine() putStrLn ("The answer is " ++ show(fib(read(x))))
I'd agree for some definition of 'early'. I'll elaborate: This entire discussion is about 'breaking a cyclic graph of conceptual dependencies'. Unfortunately, I don't think it can be done well in short amount of time. The above code snippet contains typeclasses (show, read, monadic IO, lists), syntactic sugar (do, <-). When you say a 'newbie' should be able to write that early on, I'd interpret that as 'a newbie should be able to regurgitate this early on' because the next thing a newbie might want to do is try to divide the result of fib by a float and wonder why he can't do that, or try to debug his fib implementation by trying to insert a putStrLn. There are numerous ways to frustration unless the newbie is comfortable with typeclasses, monads, etc. This happens all the time when somebody is learning a new language, but it's most problematic for haskell because the breadth of knowledge (of various concept of the language) a learner has to gather before he can dive deep (formulation, compilation, execution, debugging) into an actual (even trivial) program is larger than all popular languages out there. In every language, the most powerful features make their ways into the most basic elements (as they should so that the entire language benefits, but then, lists are monads?!?!). Learners of C++ with a C background are not as much troubled by "cout << yadda << endl;" even though there is operator overloading, references and the streams class hieararchy in that statement. You can close your eyes and pretend that cout is just magic and re-visit that node when you are comfortable with classes. I don't think we can break cycles easily like that in Haskell. The mental load is very high, and with concerns about language features vs complexity even in other languages (see http://lambda-the-ultimate.org/node/view/1155) I think we are observing a new phenomenon: languages worth learning from now on will be increasingly difficult (heck, even Perl is difficult now), and we'll have to do away with 'tutorials' mostly. In fact what we have are not really tutorials (YAHT is a small book! compare that with http://www.ocaml-tutorial.org/). I think it's a tall order for a 'tutorial' to teach Haskell (which may be why we end up reading 4-5 of them). In fact Hudak's Haskell book was the first introductory language book I'd ever bought. That's why I think tutorials can have be frustrating and it takes a well edited book and . Cheers, Koray

S Koray Can wrote:
As a newbie... I agree that a newbie should be able to write this fairly early on:
main = do x <- getLine() putStrLn ("The answer is " ++ show(fib(read(x))))
I'd agree for some definition of 'early'. I'll elaborate: [snip]
The above code snippet contains typeclasses (show, read, monadic IO, lists), syntactic sugar (do, <-). When you say a 'newbie' should be able to write that early on, I'd interpret that as 'a newbie should be able to regurgitate this early on'
Well, I'm a newbie, and I wrote it. I have "enough" understanding to generate that code, even if I don't understand it all. This is what I know: * x is a string, fib wants an int, and "read" turns a string into a number. * "The answer is " is a string so you need ++. ++ expects a string, and "show" turns a number into a string. So, yes, I need *basic* knowledge of types (strings vs numbers) and the functions that convert from one to the other. But that's it. I don't need to know that "do" and "<-" are syntactics sugar, or what a monad is (heck, I don't know those things). I think that the following is suitable for chapter 1: --//-- main = do putStrLn "What is your name? " name <- getLine putStrLn("Hello " ++ name) --//-- You don't need to learn about monads, or classes or lists for this. Yes, not even lists ("Use ++ to catenate strings"). All you need to know is strings, and that "name <- getLine" gets a line from input and puts it in 'name'. I think that this is suitable for chapter 2: --//-- main = do putStrLn "Please type a word:" word <- getLine putStrLn("This word has " ++ (show( length word)) ++ " letters") --//-- Here you learn about numbers, and converting numbers to strings (show). And this is for chapter 3: --//-- main = do putStrLn "Please type a number:" number <- getLine putStrLn (number ++ "! = " ++ (show (fac read(number))) --//-- Here you learn about converting a string to number. At some point between chapters 1 and 3 you'd learn how to write 'fac' (I guess chapter 1). Cheers, Daniel. -- /\/`) http://oooauthors.org /\/_/ http://opendocumentfellowship.org /\/_/ \/_/ I am not over-weight, I am under-tall. /

On 12/22/05, Daniel Carrera
S Koray Can wrote:
As a newbie... I agree that a newbie should be able to write this fairly early on:
main = do x <- getLine() putStrLn ("The answer is " ++ show(fib(read(x))))
I'd agree for some definition of 'early'. I'll elaborate: [snip]
The above code snippet contains typeclasses (show, read, monadic IO, lists), syntactic sugar (do, <-). When you say a 'newbie' should be able to write that early on, I'd interpret that as 'a newbie should be able to regurgitate this early on'
Well, I'm a newbie, and I wrote it. I have "enough" understanding to generate that code, even if I don't understand it all. This is what I know:
* x is a string, fib wants an int, and "read" turns a string into a number. * "The answer is " is a string so you need ++. ++ expects a string, and "show" turns a number into a string.
Actually, it's a bit more than that (but still not harder than a newbie would be able to grasp in the first chapter). 'read' convertes a string into *any* readable value. So 'read "(4,1.23,'c')"' would convert a string into type '(Integer,Double,Char)'. Likewise 'show' converts any showable value to a string. This include numbers, but also includes a host of other values. /S -- Sebastian Sylvan +46(0)736-818655 UIN: 44640862

Hello Daniel, Thursday, December 22, 2005, 3:13:06 PM, you wrote: DC> Well, I'm a newbie, and I wrote it. I have "enough" understanding to DC> generate that code, even if I don't understand it all. This is what I know: please, don't learn Haskell!!! we will test different tutorials on you! :))) -- Best regards, Bulat mailto:bulatz@HotPOP.com

Peter Simons wrote:
In my humble opinion, it's unfortunate that many tutorials and introductionary texts leave the impression that monadic code would be something utterly different than "normal" Haskell code. I feel it intimidates the reader by making a monad appear like black magic, even though it's little more than syntactic sugar to describe implicit function arguments.
I'm scared of monads :) I really don't know what a monad is. All I know is that you need it for IO because IO implies side-effects and I know that "Monad" is a very scary-looking word :)
If we'd have an opaque "World" type instead of the IO monad, 'putStrLn' would be:
putStrLn :: String -> World -> World
That seems less scary. Cheers, Daniel. -- /\/`) http://oooauthors.org /\/_/ http://opendocumentfellowship.org /\/_/ \/_/ I am not over-weight, I am under-tall. /

Daniel Carrera writes:
I'm scared of monads :) I really don't know what a monad is.
Neither do I, but that doesn't mean that I can't use just fine. ;-)
putStrLn :: String -> World -> World
That seems less scary.
Things become a lot clearer when you think about how to print _two_ lines with that kind of function. You'd write: f :: World -> World f world = putStrLn "second line" (putStrLn "first line" world) The 'world' parameter forces the two functions into the order you want, because printing "second line" needs the result of printing "first line" before it can be evaluated. However, writing complex applications with that kind of API would drive you nuts, so instead you can say f :: IO () f = do putStrLn "first line" putStrLn "second line" and it means the exact same thing. Curiously enough, if you check out the reference documentation at: http://haskell.org/ghc/docs/latest/html/libraries/base/Control-Monad-ST.html... ..., you'll find that a "World" type actually exists. Peter

Hi,
Hugs Interpreter only Suitable for learning. You'll need GHC for serious work.
This is putting Hugs down quite a bit. I personally prefer Hugs, and use it for serious work (including developing a Haskell compiler, and 4 years of academic study and counting). About the only thing it doesn't do is produce standalone binaries. I would have actually said Hugs, and especially the Windows front end WinHugs was a lot more suitable for beginners than GHC, but the wiki page very much gives the other impression. Thanks Neil

Hello Neil, Tuesday, December 20, 2005, 11:52:51 PM, you wrote: NM> Hi,
Hugs Interpreter only Suitable for learning. You'll need GHC for serious work.
NM> This is putting Hugs down quite a bit. I personally prefer Hugs, and NM> use it for serious work (including developing a Haskell compiler, and NM> 4 years of academic study and counting). for me, Hugs and especiall WinHugs is an amazing tool to develop programs that then will be compiled by GHC. they have a greatest level o compatibility while Hugs loads programs 10 times faster than GHCi and have much more helpful environment (especially WinHugs 2005) -- Best regards, Bulat mailto:bulatz@HotPOP.com

Neil Mitchell
I would have actually said Hugs, and especially the Windows front end WinHugs was a lot more suitable for beginners than GHC, but the wiki page very much gives the other impression.
Which page are you referring to? I went to look, but couldn't find any page discussing the compiler/interpreter options with reasonable detail and focus. -k -- If I haven't seen further, it is by standing in the footprints of giants

On Tuesday 20 December 2005 20:58, Peter Simons wrote:
Daniel Carrera writes:
I'm scared of monads :) I really don't know what a monad is.
Neither do I, but that doesn't mean that I can't use just fine. ;-)
putStrLn :: String -> World -> World
That seems less scary.
Things become a lot clearer when you think about how to print _two_ lines with that kind of function. You'd write:
f :: World -> World f world = putStrLn "second line" (putStrLn "first line" world)
The 'world' parameter forces the two functions into the order you want, because printing "second line" needs the result of printing "first line" before it can be evaluated.
However, writing complex applications with that kind of API would drive you nuts,
and would also be unsafe without some kind of strong guarantee that each single 'world' value is unique. (This is how they do it in Clean.) Imagine g :: World -> World g world = let world' = putStrLn "first line" world in putStrLn "second line" world -- oops, forgot the "'"
so instead you can say
f :: IO () f = do putStrLn "first line" putStrLn "second line"
and it means the exact same thing.
/and/ it guarantees that 'world' cannot be accidentally duplicated because it is not directly accessible to the program, thus there is only one 'world' ever existing at the same time, thus all IO actions are cleanly sequenced according to the data dependencies.
Curiously enough, if you check out the reference documentation at:
http://haskell.org/ghc/docs/latest/html/libraries/base/Control-Monad- ST.html#t%3ARealWorld
..., you'll find that a "World" type actually exists.
Ben

On 20/12/05, Benjamin Franksen
On Tuesday 20 December 2005 20:58, Peter Simons wrote:
Daniel Carrera writes:
I'm scared of monads :) I really don't know what a monad is.
Neither do I, but that doesn't mean that I can't use just fine. ;-)
putStrLn :: String -> World -> World
That seems less scary.
Things become a lot clearer when you think about how to print _two_ lines with that kind of function. You'd write:
f :: World -> World f world = putStrLn "second line" (putStrLn "first line" world)
The 'world' parameter forces the two functions into the order you want, because printing "second line" needs the result of printing "first line" before it can be evaluated.
However, writing complex applications with that kind of API would drive you nuts,
and would also be unsafe without some kind of strong guarantee that each single 'world' value is unique. (This is how they do it in Clean.) Imagine
g :: World -> World g world = let world' = putStrLn "first line" world in putStrLn "second line" world -- oops, forgot the "'"
Well, this would just cause the first line to be ignored, wouldn't it? I suppose it depends on one's perspective, and what the World type really looks like. If you're cheating by threading a trivial value, and getting what are supposed to be pure functions to have side effects, then this is a problem. If World is a suitable type for holding information about the actions to eventually perform based on user input, then this will work just fine (though it's likely a bug the way that it's written). To me, this view doesn't seem any less scary than the monadic approach. You've just moved the scary part (if any) into the World type. I believe that a type somewhat along the lines of [Request] -> [Response] was at one point used for this. At some point you should really stop caring exactly how it's implemented though, and simply regard these IO actions as the sum of their parts. You have a bunch of primitives (getChar :: IO Char, putChar :: Char -> IO (), etc) that describe actions to be performed, and some operations, the monad operations on IO included, for combining them into composite actions. A simple example of one of these combining operations is the sequencing operation: (>>) :: IO a -> IO b -> IO b If x and y are IO actions, then (x >> y) is just an IO action which performs x, throws away any result, and then performs y, returning the result of that. For example, (putStrLn xs) is an action which prints the string xs on the screen, and (putStrLn "Hello" >> putStrLn "World") will print the strings "Hello" and "World" on subsequent lines. What if we don't want to throw away the result of the first operation? Well, there is a slightly more complicated version of the sequencing operation for that: (>>=) :: IO a -> (a -> IO b) -> IO b Now, this might seem scary at first, but all that it is doing is chaining actions together in sequence. The expression (x >>= f) produces the action which executes the action x, and applies f to the result of that action, which gives a new action that it executes in turn. As an example, getLine :: IO String, is an action which gets a line of text from the user. (getLine >>= \x -> putStrLn x) is an action which gets a line of text from the user, and then prints it back out. By understanding the primitives and the combiners, it's possible to understand everything there is to know about IO in Haskell. You don't actually need to look at how it's implemented (and probably shouldn't rely on one implementation too much). Let the RTS worry about the data structures used to represent your actions, exposing the implementation details just makes things more complicated. This is not to say that understanding monads in general isn't worthwhile, it very much is. It's also not to say that monads should always be treated like black boxes, as most often they aren't at all black boxes. However, it's possible for the library designer to give you a monad whose inner workings you can't inspect directly, and in the case of IO, that's basically what has been done. It should be respected, because it actually simplifies matters not to worry about the implementation. - Cale

On Tue, Dec 20, 2005 at 10:04:16PM +0100, Benjamin Franksen wrote:
and would also be unsafe without some kind of strong guarantee that each single 'world' value is unique. (This is how they do it in Clean.) Imagine
g :: World -> World g world = let world' = putStrLn "first line" world in putStrLn "second line" world -- oops, forgot the "'"
A more scary example: getLine :: World -> (World, String) getTwoLines :: World -> (World, String, String) getTwoLines world = let (world', line1) = getLine world (world'', line2) = getLine world -- oops, should use world' here in (world'', line1, line2) So we forgot about world', but used line1, which was produced together with world'. Best regards Tomasz -- I am searching for a programmer who is good at least in some of [Haskell, ML, C++, Linux, FreeBSD, math] for work in Warsaw, Poland

On Tue, 2005-12-20 at 20:58 +0100, Peter Simons wrote:
Curiously enough, if you check out the reference documentation at:
http://haskell.org/ghc/docs/latest/html/libraries/base/Control-Monad-ST.html...
..., you'll find that a "World" type actually exists.
While that is true in GHC it is not required by Haskell. The concrete implementation of IO is compiler specific. Also worth noting is that there are (two that I know of) languages that employ an explicit world parameter to do IO: Clean and Mercury. Cheers, Bernie.

Paul Moore
One thing I'd consider adding is something along the lines of a section:
== So how do I write "Hello, world"? ==
I've gone and done it. I've perhaps been heavy handed on the original page, so feel free to complain and/or fix it. -k -- If I haven't seen further, it is by standing in the footprints of giants

On 2005-12-20, Daniel Carrera
Hi all,
I've finished a first draft of what I call "First steps in Haskell". It's intended to be the very first thing a new user sees when they decide to try out Haskell.
I should point out a parallel effort that a few of us have worked on from time to time: darcs get --partial http://darcs.complete.org/haskell-v8 Please feel free to darcs send any patches. -- John
participants (27)
-
Benjamin Franksen
-
Bernard Pope
-
Bill Wood
-
Bulat Ziganshin
-
Cale Gibbard
-
Creighton Hogg
-
Daniel Carrera
-
Daniel Fischer
-
Donn Cave
-
Hal Daume III
-
Henning Thielemann
-
Jared Updike
-
John Goerzen
-
John Meacham
-
Ketil Malde
-
Neil Mitchell
-
Paul Moore
-
Peter Simons
-
Philippa Cowderoy
-
pkeeken@students.cs.uu.nl
-
Ralf Hinze
-
Robin Green
-
S Koray Can
-
Sebastian Sylvan
-
Tomasz Zielonka
-
Udo Stenzel
-
Wolfgang Jeltsch