2012-04-10 12 views
5

Un esempio giocattolo, ma ancora frustrante:Haskell getta un errore di analisi in un posto strano

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 mi dice che ho un Parse error in pattern: putStrLn e io non riesco a capire il motivo per cui non dovesse analizzare.

+1

Ok, questo funziona se aggiungo le parentesi graffe per i blocchi e il punto e virgola alla fine di ogni 'istruzione' - ma è quella la soluzione consigliata? (sembra un po 'non funzionale: P) – agam

+0

Puoi fingere che il punto e virgola e le parentesi graffe siano già lì, ma invisibili. (Ci sono regole per dove vanno le parentesi graffe e il punto e virgola). –

risposta

10

Correzione:

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 

Correzione: Le righe all'interno di un blocco do devono essere allineate.

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

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

Fix 2: Usando let all'interno di un blocco do, non usare in.

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

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

Fix 3: Usa forM_ (che restituisce (), vuoto pseudonimo) al posto di forM (che restituisce una lista).

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

Così forM_ potrebbe (quasi) essere scritta in questo modo:

forM_ xs f = do forM xs f 
       return() 

Modifica minore: non ti servono return qui:

do func1 
    x <- func2 
    return x 

si può cambiare a l'equivalente,

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

Wow ... grazie !! – agam

4

Si superano le righe nei blocchi. Inoltre, non è necessario un in per le dichiarazioni let nei blocchi do.

questo funziona per 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) 

È inoltre possibile strutturare in questo modo:

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 

(che consente di evitare le parentesi, in alternativa, mettere il do alla fine del \num -> e allineare le dichiarazioni successive)

Problemi correlati