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.
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
You over-indent lines in your do-blocks. Furthermore, you don't need an in
for let
statements in do
-blocks.
This works for me:
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
forM numberCodes (\(num,code) ->
putStrLn $ "Got code " ++ show code ++ " for " ++ show num)
You can also structure it like this:
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
forM numberCodes $ \(num,code) ->
putStrLn $ "Got code " ++ show code ++ " for " ++ show num
(which lets you avoid the parentheses; alternatively, put the do
at the end of the \num ->
and line up subsequent statements)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With