You can pseudo-compile / unwind the monadic block to see how it works:
f 3 = do v <- getLine vs <- f 2 -- (will return a list with 2 lines from stdin return $! v : vs f 2 = do v <- getLine vs <- f 1 -- (will return singleton list with a line from stdin) return $! v : vs f 1 = do v <- getLine vs <- f 0 -- (will return an empty list) return $! v : vs f 0 = return []
So, it will getLine
3 times, and then create a list of lines, the first line will be the first value in the list.
Each time you see return
in a monadic expression, you put a value in it. Each time you see <-
(bind) in a monadic expression, you take values ββfrom it. In the case of the IO
monad, you always put and take out one of the monads. On the contrary, the list monad can "pull out" (bind) consecutive values.
source share