foldLeft (\_ x -> putStrLn x) (pure ()) ("2":."1":.Nil)
Why the above code outputs
1
rather than
2
1
I am doing exercise of fp-course
https://github.com/system-f/fp-course/blob/5e0848b4eacb3ddff65553ab5beb6447b73f61b3/src/Course/FileIO.hs#L97
I have figured 2 solutions for this.
printFiles ps = void . sequence $ (uncurry printFile) <$> ps
printFiles = foldLeft (\_ (fp, content) -> printFile fp content) (pure ())
The first is right and can print as question's ask.
>> :main "share/files.txt"
============ share/a.txt
the contents of a
============ share/b.txt
the contents of b
============ share/c.txt
the contents of c
The second print as follow.
>> :main "share/files.txt"
============
share/c.txt
the contents of c
It looks like pure ()
only collect the last printFile fp content
of foldLeft
.
How to make pure ()
aka IO ()
collects all putStrLn
in foldLeft
?
Because Haskell is referentially transparent, you can always answer such questions for yourself by evaluating the expression manually, i.e. inlining function calls and beta-reducing until it's obvious what's going on:
foldLeft (\_ x -> putStrLn x) (pure ()) ("2":."1":.Nil)
= {- (recursive) definition of `foldLeft` for Cons case -}
foldLeft (\_ x -> putStrLn x)
((\_ x -> putStrLn x) (pure ()) "2")
("1":.Nil)
= {- beta reduction -}
foldLeft (\_ x -> putStrLn x)
(putStrLn "2")
("1":.Nil)
= {- definition of `foldLeft` for Cons case -}
foldLeft (\_ x -> putStrLn x)
((\_ x -> putStrLn x) (putStrLn "2") "1")
Nil
= {- beta reduction -}
foldLeft (\_ x -> putStrLn x)
(putStrLn "1") -- woops, the "2" has vanished in the `_` argument
Nil
= {- definition of `foldLeft` for Nil case -}
putStrLn "1"
So that's all you get: one print of "1"
. OTOH, with Willem Van Onsem's suggestion it will be
foldLeft (\prev x -> prev >> putStrLn x) (pure ()) ("2":."1":.Nil)
= {- definition of `foldLeft` for Cons case -}
foldLeft (\prev x -> prev >> putStrLn x)
((\prev x -> prev >> putStrLn x) (pure ()) "2")
("1":.Nil)
= {- beta reduction -}
foldLeft (\prev x -> prev >> putStrLn x)
(pure () >> putStrLn "2")
("1":.Nil)
= {- definition of `foldLeft` for Cons case -}
foldLeft (\prev x -> prev >> putStrLn x)
((\prev x -> prev >> putStrLn x) (pure () >> putStrLn "2") "1")
Nil
= {- beta reduction -}
foldLeft (\prev x -> prev >> putStrLn x)
((pure () >> putStrLn "2") >> putStrLn "1")
Nil
= {- definition of `foldLeft` for Nil case -}
pure () >> putStrLn "2" >> putStrLn "1"