Haskell throws a parse error in a strange place

haskell, parse-error

Solution

Correction:

numberMapper:: IO ()
numberMapper = do
    codes <- forM [1 .. 4] $ \num -> do
        putStrLn $ "Enter a code for " ++ show num
        getLine
    let numberCodes = zip [1 .. 4] codes
    forM_ numberCodes $ \(num,code) ->
        putStrLn $ "Got code " ++ show code ++ " for " ++ show num

Fix: The lines inside a `do` block should line up.

-- wrong
a = do codes <- something
        let numberCodes = zip [1..4] codes

-- right
a = do codes <- something
       let numberCodes = zip [1..4] codes

Fix 2: When using `let` inside a `do` block, don't use `in`.

-- wrong
func = do
    let x = 17
    in print x

-- right
func = do
    let x = 17
    print x

Fix 3: Use `forM_` (which returns `()`, a.k.a. void) instead of `forM` (which returns a list).

codes <- forM [1..4] func...  -- returns a list
forM_ numberCodes $ ...       -- discards list, returns () 

So `forM_` could (almost) be written like this:

forM_ xs f = do forM xs f
                return ()

Minor change: You don't need `return` here:

do func1
   x <- func2
   return x

You can change it to the equivalent,

do func1
   func2 -- value of func2 is returned

Problem

A toy example but still frustrating: ``` numberMapper:: IO () numberMapper = do codes <- forM [1 .. 4] (\num -> do putStrLn $ "Enter a code for " ++ show num code <- getLine return code) let numberCodes = zip [1 .. 4] codes in forM numberCodes (\(num,code) -> putStrLn $ "Got code " ++ show code ++ " for " ++ show num) ``` `ghci` tells me I have a `Parse error in pattern: putStrLn` and I can't figure out why it should fail to parse.

Original source