Most Haskell tutorials teach the use of do-notation for IO.
I also started with the do-notation, but that makes my code look more like an imperative language more th
The do notation is expanded to an expression using the functions (>>=) and (>>), and the let expression. So it is not part of the core of the language.
(>>=) and (>>) are used to combine actions sequentially and they are essential when the result of an action changes the structure of the following actions.
In the example given in the question this is not apparent as there is only one IO action, therefore no sequencing is needed.
Consider for example the expression
do x <- getLine
print (length x)
y <- getLine
return (x ++ y)
which is translated to
getLine >>= \x ->
print (length x) >>
getLine >>= \y ->
return (x ++ y)
In this example the do notation (or the (>>=) and (>>) functions) is needed for sequencing the IO actions.
So soon or later the programmer will need it.