|
|
Line 1: |
Line 1: |
| People sometimes wonder how to effectively do recursion when inside a
| |
| monadic <hask>do</hask>-block. Here's some quick examples:
| |
|
| |
|
| The problem is to read 'n' lines from stdin, recursively:
| |
|
| |
| The obvious, recursive way:
| |
|
| |
| <haskell>
| |
| main = f 3
| |
|
| |
| f 0 = return []
| |
| f n = do v <- getLine
| |
| vs <- f (n-1)
| |
| return $! v : vs
| |
| </haskell>
| |
|
| |
| Runs:
| |
|
| |
| <haskell>
| |
| $ runhaskell A.hs
| |
| 1
| |
| 2
| |
| 3
| |
| ["1","2","3"]
| |
| </haskell>
| |
|
| |
| Or make it [[tail recursion|tail recursive]]:
| |
|
| |
| <haskell>
| |
| f 0 acc = return (reverse acc)
| |
| f n acc = do
| |
| v <- getLine
| |
| f (n-1) (v : acc)
| |
| </haskell>
| |
|
| |
| Or abstract the recursion pattern into a fold:
| |
|
| |
| <haskell>
| |
| f n = do
| |
| s <- foldM fn [] [1..n]
| |
| return (reverse s)
| |
|
| |
| where fn acc _ = do x <- getLine
| |
| return (x:acc)
| |
| </haskell>
| |
|
| |
| And finally, apply some functor and pointfree shortcuts:
| |
|
| |
| <haskell>
| |
| f n = reverse `fmap` foldM fn [] [1..n]
| |
| where fn acc _ = (: acc) `fmap` getLine
| |
| </haskell>
| |
|
| |
| [[Category:Code]]
| |
| [[Category:Glossary]]
| |