2010-05-31 28 views
7

he el siguiente código:extraño error en Haskell sobre sangría de if-then-else

foo :: Int -> [String] -> [(FilePath, Integer)] -> IO Int 
foo _ [] _ = return 4 
foo _ _ [] = return 5 
foo n nameREs pretendentFilesWithSizes = do 
    result <- (bar n (head nameREs) pretendentFilesWithSizes) 
    if result == 0 
    then return 0 -- <========================================== here is the error 
    else foo n (tail nameREs) pretendentFilesWithSizes 

consigo un error en la línea con el comentario anterior, el error es:

aaa.hs:56:2: 
    parse error (possibly incorrect indentation) 

Estoy trabajando con emacs, no hay espacios, y no entiendo qué hice mal.

Respuesta

11

Esto se explica en la sección "if -within- do" de Wikibooks article en la sangría de Haskell.

El problema es que a la do -desugarer, los then y else líneas se ven como nuevos estados:

do { first thing 
    ; if condition 
    ; then foo 
    ; else bar 
    ; third thing } 

Sangrado de las then y else líneas va a resolver el problema.

ACTUALIZACIÓN: Dado que este está etiquetado beginner, también a señalar que algo así sería considerada generalmente más idiomática lo siguiente en Haskell:

foo :: Int -> [String] -> [(FilePath, Integer)] -> IO Int 
foo _ [] _ = return 4 
foo _ _ [] = return 5 
foo n (r:rs) filesWithSizes = bar n r filesWithSizes >>= checkZero 
    where 
    checkZero :: Int -> IO Int 
    checkZero 0 = return 0 
    checkZero _ = foo n rs filesWithSizes 

Esto hace exactamente lo mismo que su foo, pero evita el azúcar do y utiliza la coincidencia de patrones en lugar de head y tail y la estructura de control if-then-else. Informalmente, el >>= dice aquí "saca la salida de bar... de su contenedor IO y la ejecuta a través de checkZero, devolviendo el resultado".