
L.S., In my enthusiasm to reduce imperative style coding to a minimum, I changed a program to something too lazy to do anything. The following is an extremely simplified version of the program:
import Monad
displayFile1 :: IO (IO ())displayFile1 = liftM putStr contents -- Displays nothing where contents :: IO [Char] contents = readFile "DisplayFile.lhs"
This should display the contents of a file, but nothing appears. The following function should be exactly the same, but this one does display the file:
displayFile2 :: IO () displayFile2 = do contents <- readFile "DisplayFile.lhs" putStr contents
My conclusion is, that "putStr" is evaluated strictly, while "liftM putStr" is not. I have the following questions: - Why is this difference? - Is there some method to predict whether my program is sufficiently strict to really do what it is supposed to do? - Did someone design a method to develop programs not too strict and not too lazy? - The manual "A gentle introduction to Haskell" states in section 6.3: "adding strictness flags may lead to hard to find infinite loops or have other unexpected consequences"; I would like to know when these problems arise; are these cases described somewhere? -- Met vriendelijke groet, Herzliche Grüße, Best regards, Henk-Jan van Tuyl -------------------------------------------------------------------- Festina Lente Hasten Slowly Haast U langzaam Eile langsam Skynd dig langsomt Affrettati lentamente Spěchej pomalu Skynda långsamt Desiderius Erasmus --------------------------------------------------------------------

hello, the types IO(IO ()) and IO() are not the same. think of a value of type "IO a" as a _program_ that when executed will return a result of type "a" (and while executing may print some stuff to the screen). now consider these types: putStrLn :: String -> IO () this is a _pure function_ which when given a string will return a _program_ that later when executed will print the string. note however that this function does not itself print, it simply creates a program that can print. this is the main idea that allows haskell to be pure and still manage to have printing. liftM :: (a -> b) -> IO a -> IO b this again is a pure function, that when given a function and a program, will make another program that behaves as follows (when executed): * it first executes the argument program to get an "a" * then it applies the argument function, to turn the "a" into a "b", and this is the final result. at this point you might wonder: well it is all very good that one can build these programs, but how do you execute them? a slightly simplified answer is as follows: the haskell run time system starts by evaluating the _expression_ "main :: IO ()", i.e. it will first build an IO program, and then (behind the scenece) it will execute it. the reason this is slightly simlified is that in fact the building of the program and its execution kind of progress in parallel (for more details see Simon PJ's "tackling the awkward squad" paper). now back to your question, you were wondering about: liftM putStrLn (readFile "SomeFile") :: IO (IO ()) this is a peculiar beast --- a program, that when executed will return as a result another program (a kind of meta-program) when executed this program will behave as follows: * it will execute the (readFile "SomeFile") program, and as a result it will get the contents of the file * then to get the result it will apply putStrLn to this, which will produce _another program_ (rememebr putStrLn does not print, as haskell is a pure language) at this point this new program will be returned as the result. notice that the only IO that happened was the readiong of the file. to sequence IO programs you should use on of the following: (>>=), (=<<), or simply the "do"-notation. so the above program that will first read the file, and then print its contents may be written as follows: do string <- readFile "SomeFile" putStrLn string or alternatively: putStrLn =<< readFile "SomeFile" sorry for the long post, and i hope it was useful. -iavor hjgtuyl@chello.nl wrote:
L.S.,
In my enthusiasm to reduce imperative style coding to a minimum, I changed a program to something too lazy to do anything. The following is an extremely simplified version of the program:
import Monad
displayFile1 :: IO (IO ())displayFile1 = liftM putStr contents -- Displays nothing where contents :: IO [Char] contents = readFile "DisplayFile.lhs"
This should display the contents of a file, but nothing appears. The following function should be exactly the same, but this one does display the file:
displayFile2 :: IO () displayFile2 = do contents <- readFile "DisplayFile.lhs" putStr contents
My conclusion is, that "putStr" is evaluated strictly, while "liftM putStr" is not.
I have the following questions: - Why is this difference? - Is there some method to predict whether my program is sufficiently strict to really do what it is supposed to do? - Did someone design a method to develop programs not too strict and not too lazy? - The manual "A gentle introduction to Haskell" states in section 6.3: "adding strictness flags may lead to hard to find infinite loops or have other unexpected consequences"; I would like to know when these problems arise; are these cases described somewhere?

At Thu, 16 Sep 2004 18:26:35 +0200, hjgtuyl@chello.nl wrote:
L.S.,
In my enthusiasm to reduce imperative style coding to a minimum, I changed a program to something too lazy to do anything. The following is an extremely simplified version of the program:
import Monad
displayFile1 :: IO (IO ())displayFile1 = liftM putStr contents -- Displays nothing where contents :: IO [Char] contents = readFile "DisplayFile.lhs"
This should display the contents of a file, but nothing appears. The following function should be exactly the same, but this one does display the file:
displayFile2 :: IO () displayFile2 = do contents <- readFile "DisplayFile.lhs" putStr contents
My conclusion is, that "putStr" is evaluated strictly, while "liftM putStr" is not.
Has nothing to do with strict/lazy.
I have the following questions: - Why is this difference?
Notice the type of displayFile1 vs displayFile2 IO(IO()) vs IO () While displayFile2 actually prints something, displayFile1 mearly returns an 'action', which will print something if you 'evaluate' it. Here is an example of how to use displayFile1 the way you wrote it: import Monad displayFile1 :: IO (IO ()) displayFile1 = liftM putStr contents where contents :: IO [Char] contents = readFile "DisplayFile.lhs" doDisplayFile :: IO () doDisplayFile = displayFile1 >>= \action -> action or alternately, you could write doDisplayFile like this (same thing, just a different syntax): doDisplayFile :: IO () doDisplayFile = do action <- displayFile1 action if you wanted displayFile1 to behave more like displayFile2 you could write it like this: displayFile3 :: IO () displayFile3 = contents >>= putStrLn where contents :: IO [Char] contents = readFile "DisplayFile.lhs" or, like this (same thing, different syntax) displayFile3 :: IO () displayFile3 = do c <- contents putStrLn c where contents :: IO [Char] contents = readFile "DisplayFile.lhs" Jeremy Shaw -- This message contains information which may be confidential and privileged. Unless you are the addressee (or authorized to receive for the addressee), you may not use, copy or disclose to anyone the message or any information contained in the message. If you have received the message in error, please advise the sender and delete the message. Thank you.

This should *not* display anything. Look at the types! displayFile1 returns a value that is the "displaying action". It does not "run" it. Replace "liftM" with "(=<<)" or use "join displayFile1" if you want to run the displaying action. mike
displayFile1 :: IO (IO ()) displayFile1 = liftM putStr contents -- Displays nothing where contents :: IO [Char] contents = readFile "DisplayFile.lhs"
This should display the contents of a file, but nothing appears.
participants (4)
-
hjgtuyl@chello.nl
-
Iavor S. Diatchki
-
Jeremy Shaw
-
Mike Gunter