Search code examples
haskellparse-error

Haskell throws a parse error in a strange place


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.


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