Recursion in a monad

From HaskellWiki
Revision as of 06:36, 29 November 2006 by DonStewart (talk | contribs) (more)
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

People sometimes wonder how to effectively do recursion when inside a monadic do-block. Here's some quick examples:

The problem is to read 'n' lines from stdin, recursively:

The obvious, recursive way:

main = f 3

f 0 = return []
f n = do v  <- getLine
         vs <- f (n-1)
         return $! v : vs

Runs:

    $ runhaskell A.hs
    1
    2
    3
    ["1","2","3"]

Or make it tail recursive:

f 0 acc = return (reverse acc)
f n acc = do
    v  <- getLine
    f (n-1) (v : acc)

Or abstract the recursion pattern into a fold:

f n = do
    s <- foldM fn [] [1..n]
    return (reverse s)

  where fn acc _ = do x <- getLine
                      return (x:acc)

And finally, apply some functor and pointfree shortcuts:

f n = reverse `fmap` foldM fn [] [1..n]
    where fn acc _ = (: acc) `fmap` getLine