Doing IO in foldr repeats lines?
Hi all The following code:
module Main (main) where
import IO
main :: IO() main = do _ <- foldl foo (return 14) ["qq\n", "ww\n", "ee\n"] putStr ""
foo :: IO Int -> String -> IO Int foo io_l s = do l <- io_l () <- putStr s io_l
prints (with both GHC and hugs): qq ww qq ee qq ww qq and I really don't understand why. Is the code re-evaluated every time foldl is expanded or something? Thanks Ian, confused
At 21:17 2001-01-20 +0000, Ian Lynagh wrote:
main = do _ <- foldl foo (return 14) ["qq\n", "ww\n", "ee\n"] putStr ""
foo :: IO Int -> String -> IO Int foo io_l s = do l <- io_l () <- putStr s io_l
It repeats lines
and I really don't understand why. Is the code re-evaluated every time foldl is expanded or something?
Since the result type of foo is IO Int, it is building an IO action, in other words it is calculating a sequence of effects. The combined effects are performed by main. Repetition occurs due to the structure of foo. Notice that its action consists of first performing io_l, then putting a string, and then performing io_l _again_. If io_l prints the lines qq, ww, and qq, then the result will involve two such triplets. Try this. Remove either of the occurrences of io_l from the do block, and you will see quite different results. -- Scott Turner p.turner@computer.org http://www.billygoat.org/pkturner
On Sat, Jan 20, 2001 at 05:08:48PM -0500, Scott Turner wrote:
At 21:17 2001-01-20 +0000, Ian Lynagh wrote:
main = do _ <- foldl foo (return 14) ["qq\n", "ww\n", "ee\n"] putStr ""
foo :: IO Int -> String -> IO Int foo io_l s = do l <- io_l () <- putStr s io_l
It repeats lines
and I really don't understand why. Is the code re-evaluated every time foldl is expanded or something?
Since the result type of foo is IO Int, it is building an IO action, in other words it is calculating a sequence of effects. The combined effects are performed by main.
Thanks, a private mail showing the evaluation highlighted my stupidity wonderfully :-) I now see what's going on and a return l instead of io_l as the last line is what I wanted. The mixture of io_l and return bar also explains why I was seeing really random looking output unlike the nice pattern of the more minimal case :-) Thanks Ian
Ian Lynagh wrote:
main :: IO() main = do _ <- foldl foo (return 14) ["qq\n", "ww\n", "ee\n"] putStr ""
foo :: IO Int -> String -> IO Int foo io_l s = do l <- io_l () <- putStr s io_l
prints (with both GHC and hugs):
qq ww qq ee qq ww qq
and I really don't understand why. Is the code re-evaluated every time foldl is expanded or something?
Nobody seems to have answered yet, so I try to explain it. Look at your definition of foo: it actually duplicates its argument action io_l. For the first application io_l is (return 14). Let's call that io_l0. The resulting action is io_l1 = do { l <- return 14; () <- putStr "qq"; return 14 } which is passed at the next application. The result is io_l2 = do { l <- do { l <- return 14; () <- putStr "qq"; return 14 } ; () <- putStr "ww" ; do { l <- return 14; () <- putStr "qq"; return 14 } } This can be reformulated as io_l2'= do { l <- return 14 ; () <- putStr "qq" ; l <- return 14 ; () <- putStr "ww" ; l <- return 14 ; () <- putStr "qq" ; return 14 } And so on. Finally the complete action (io_l3) is executed by running main and produces the output you observe. Hope this helps, - Andreas -- Andreas Rossberg, rossberg@ps.uni-sb.de :: be declarative. be functional. just be. ::
participants (3)
-
Andreas Rossberg -
Ian Lynagh -
Scott Turner