Search code examples
haskellgetlinenotation

Haskell: words count from a getLine without the "do" notation


How do I write the following function without using the "do" notation?

wordsCount =  do 
    putStr "Write a line and press [enter]:\n"
    s <- getLine
    putStr $ show $ length . words $ s
    putChar '\n'

Solution

  • Instead of using do, you can use >> and >>=:

    wordsCount = putStr "Write a line and press [enter]:\n" >> getLine >>= putStr . show . length . words >> putChar '\n'
    

    Or making it easier to read:

    wordsCount = putStr "Write a line and press [enter]:\n" >>
        getLine >>=
        putStr . show . length . words >>
        putChar '\n'
    

    A more straight-forward translation would be:

    wordsCount = putStr "Write a line and press [enter]:\n" >>
        getLine >>=
        \s -> (putStr $ show $ length $ words s) >>
        putChar '\n'
    

    Basically the compiler converts such do-notation blocks to its monadic equivalent (using only >> and >>=). do is only syntactical sugar such that one does not have to write >>= each time and/or mange variables.

    Additional notes:

    • as @ChadGilbert said in his comment, the parenthesis should be wrapped around the function, excluding the \s -> such that the s can be used later on in the program, for example:

      -- This is not an equivalent program
      wordsCount = putStr "Write a line and press [enter]:\n" >>
          getLine >>=
          \s -> (putStr $ show $ length $ words s) >>
          putChar '\n' >>
          putStrLn s -- repeat s
      
    • Instead of using putStr and putChar, you can use putStrLn. For example:

      wordsCount = putStr "Write a line and press [enter]:\n" >>
          getLine >>=
          putStrLn . show . length . words