I was curious about how the “input redirection” program on page 170 of Learn You a Haskell for Great Good (#ad) (LYAH) worked, so I typed it into a file named do1.hs, with one additional line:
import Data.Char main = do contents <- getContents putStrLn "dude" putStr $ map toUpper contents
The line I added is the putStrLn "dude"
line.
I compiled it like this:
$ ghc do1.hs
Then I ran it like this:
$ ./do1 < do1.hs
Can you guess what the output was?
This space intentionally left blank so you can think about it ...
.
.
.
Here’s the output:
dude IMPORT DATA.CHAR MAIN = DO CONTENTS <- GETCONTENTS PUTSTRLN "DUDE" PUTSTR $ MAP TOUPPER CONTENTS
That’s pretty cool.
I ran this code because I wasn’t 100% sold on the description of the do
block code on page 172, but the description is correct. The putStr
and getContents
functions have a lazy interaction that is, well, cool.
Follow-up: The same example in Scala
Hmph, I guess that code isn’t that exciting ... if I use the using
construct that I described in the Scala Cookbook, that Haskell code is close to being the same as this:
using(Source.fromFile("/etc/passwd")) { source => { lazy val lines = source.getLines println("dude") lines.map(_.toUpperCase).foreach(println) }}
In this code getLines
returns an iterator. I’m actually interested in the Haskell hGetContents
function, which LYAH says returns a Handle. At the moment I don’t know how that maps to Scala, as in I don’t know if a Haskell Handle
is more similar to a Scala File
or an Iterator
.
Note that I put the lazy
in there because I think that’s closer to what Haskell does. Also note that in Scala that last line can be written a little more directly like this:
lines.foreach(s => println(s.toUpperCase))
I think I was just confused with the Haskell code by the do
block. For some reason I always want it to be a loop, which it is not.
(The using
block isn’t necessary for this example, but it does automatically close the file, which is nice.)