Search code examples
haskellio

Haskell: How getContents works?


Why doesn't the following program print my input? It seems that putStr is not taking the input. How does getContents work?

main = do 
    contents <- getContents
    when (length contents < 10) $ putStr contents    

However, this program prints the input line by line:

main = do 
    contents <- getContents
    putStr contents    

Solution

  • getContents gets everything. Linebuffering makes it line-by-line

    getContents gets the entire input from a handle (eg file or user input), so your program

    main = do 
        contents <- getContents
        putStr contents
    

    reads the entire contents of the standard input and prints it. The only reason you see this line by line is that it's using linebuffering on the terminal, so getContents gets its incoming String a line at the time.

    Lazy evaluation

    Haskell uses lazy evaluation, which means it only calculates something when it has to - it doesn't need calculate the end of the string you're printing to print the start of it, so it doesn't bother, and just prints what it has now. This lazy functions are able to return partial results when they can, rather than having to calculate everything first.

    A line at a time

    You appear in comments to want to only print lines when they're short like this session:

    don't print this it's long
    print this
    print this
    this is also too long
    boo!
    boo!    
    

    but since getContents is all the input, it won't print anything unless the total length is less than 10. What you were after was something where it treats each line separately, more like

    main = do
      contents <- getContents
      putStrLn . unlines . filter short . lines $ contents
    
    short xs = length xs <= 10