2012-04-10 2 views
5

Игрушечный пример, но по-прежнему разочаровывает:Haskell бросает синтаксическую ошибку в незнакомом месте

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 говорит мне, что есть Parse error in pattern: putStrLn, и я не могу понять, почему он должен не разобрать.

+1

Хорошо, это работает, если я добавлю фигурные скобки для блоков do и точек с запятой в конце каждого «заявления» - но является ли это рекомендуемым решением? (кажется немного неработоспособным: P) – agam

+0

Вы можете притворяться, что точки с запятой и фигурные скобки уже есть, но невидимы. (Есть правила, по которым идут автоматические скобки и точки с запятой.) –

ответ

10

Исправление:

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: Строки внутри блока do должны выстраиваться в линию.

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

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

Fix 2: При использовании let внутри do блока, не используйте in.

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

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

Fix 3: Использование forM_ (который возвращает (), а.к.а. недействительным) вместо forM (который возвращает список).

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

Так forM_ может (почти) записывается следующим образом:

forM_ xs f = do forM xs f 
       return() 

Незначительные изменения: Вам не нужно return здесь:

do func1 
    x <- func2 
    return x 

Вы можете изменить его эквивалент,

do func1 
    func2 -- value of func2 is returned 
+0

Ничего себе ... спасибо! – agam

4

Вы переступаете строки в своих блоках. Кроме того, вам не нужен in для операторов let в do -блоках.

Это работает для меня:

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) 

Вы также можете структурировать это следующим образом:

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 

(который позволяет избежать круглые скобки, в качестве альтернативы, положить do в конце \num -> и выстраивать последующие заявления)