2012-06-03 14 views
15

estado rascándose la cabeza durante un día sobre éste.expresiones condicionales en Monádicos - GHC compila, cábala se niega

tengo unas pocas funciones en mi código que se ven así:

function :: IO (Maybe Whatever) 
function = do 
    monadFun 
    yaySomeIO 
    status <- maybeItWillFail 
    if checkStatus status -- Did we succeed? 
    then monadTime >>= return . Just . processItPurely 
    else return Nothing 

ghci se cargará y ejecutará esta forma interactiva sin problemas, y GHC compilarlo felizmente. La ejecución de este través de Cabal, sin embargo, me da esto:

myProgram.hs:94:16: 
Unexpected semi-colons in conditional: 
    if checkStatus status; then monadTime >>= return . Just . processItPurely; else return Nothing 

Perhaps you meant to use -XDoAndIfThenElse? 

Y lo que esta opción es -XDoAndIfThenElse, me parece que no puede encontrar un rastro de ella en cualquier lugar en cualquier documentación. ¿Por qué está cabal (o es este ghc en este momento?) Gritándome por usar puntos y comas que IT puso allí en primer lugar? ¿O está usando expresiones monádicas en declaraciones if-then-else simplemente una mala idea?

Tenga en cuenta que Cabal no se queja de esto en absoluto:

case checkStatus status of 
    True -> monadTime >>= return . Just . processItPurely 
    _ -> return Nothing 

... excepto que esta es feo como el infierno y yo no se desea poner esto en mi código. ¿Alguien puede decirme qué está pasando? Por favor y gracias de antemano.

Respuesta

27

La forma "correcta" de sangría if -expresiones en un -bloque do es para sangrar los else y then líneas más allá de la if, como este.

function = do 
    monadFun 
    yaySomeIO 
    status <- maybeItWillFail 
    if checkStatus status -- Did we succeed? 
     then monadTime >>= return . Just . processItPurely 
     else return Nothing 

Esto se debe a líneas con la misma cantidad de sangría en un bloque do son normalmente tratados como estados separados.

Sin embargo, existe una extensión llamada DoAndIfThenElse que permitirá escribir de la manera que lo hizo. Esta extensión se hizo estándar en Haskell 2010, por lo que GHC lo habilita por defecto.

Cabal tiende a exigirle que sea más explícito sobre estas cosas, por lo que para usarlo en Cabal, debe mencionarlo en su archivo .cabal o agregar {-# LANGUAGE DoAndIfThenElse #-} a la parte superior de su módulo.

+3

¡Gracias, solo agregaré las sangrías según sea necesario! –

6

Esto no es una respuesta directa a su pregunta, pero se puede eliminar si la declaración mediante el aprovechamiento de MaybeT. Además, foo >>= return . bar es lo mismo que bar <$> foo. (<$> es de Control.Applicative, y es lo mismo que fmap)

function :: MaybeT IO Whatever 
function = do 
    lift monadFun 
    lift yaySomeIO 
    status <- lift maybeItWillFail 
    guard (checkStatus status) 
    processItPurely <$> lift monadTime 

La única molestia es el esparcimiento gratuito de lift s, pero hay maneras de deshacerse de ellos.

+1

Una vez que haya terminado esta aplicación, debo volver a abrir los libros de Haskell. Seguro que he oído hablar de cosas como Applicative y Functors, pero nunca los he usado. Si más conocimiento puede hacer que mi código sea más sexy, estoy totalmente de acuerdo. –