2012-06-03 14 views
15

Mi stavo grattando la testa per un giorno su questo.Espressioni monadiche in condizionali - Compensa GHC, rifiuto cabal

Ho un paio di funzioni nel mio codice che assomigliano a questo:

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 sarà caricare ed eseguire questo modo interattivo senza problemi, e GHC sarà compilarlo felicemente. L'esecuzione di questo attraverso la cabala, però, mi dà questo:

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? 

E qualunque cosa questa opzione -XDoAndIfThenElse è, io non riesco a trovare una traccia di esso ovunque in tutta la documentazione. Perché la cabala (o è questo ghc a questo punto?) Mi sta urlando per usare i semi-colon che l'IT ha messo lì in primo luogo? Oppure usare espressioni monadiche in istruzioni if-then-else è solo una cattiva idea?

noti che cabala non si lamenta questo a tutti:

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

... tranne che questa è brutto come l'inferno e non avevo mai voglia di mettere questo nel mio codice. Qualcuno può dirmi cosa sta succedendo? Per favore e grazie in anticipo.

risposta

27

Il modo "corretto" di indentazione if -expressions in do -block è far rientrare le linee else e then oltre la if, come questo.

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

Questo perché linee con la stessa quantità di rientro in un blocco do vengono normalmente trattati come istruzioni separate.

Tuttavia, esiste un'estensione denominata DoAndIfThenElse che ti consentirà di scriverlo come hai fatto tu. Questa estensione è stata resa standard in Haskell 2010, motivo per cui GHC lo abilita di default.

Cabal tende a richiedere di essere più esplicito di queste cose, in modo da utilizzarlo in Cabal, è necessario o menzionarlo nel file .cabal o aggiungere {-# LANGUAGE DoAndIfThenElse #-} alla parte superiore del modulo.

+3

Grazie, aggiungerò i trattini se necessario! –

6

Questa non è una risposta diretta alla tua domanda, ma puoi eliminare la dichiarazione if sfruttando MaybeT. Inoltre, foo >>= return . bar corrisponde a bar <$> foo. (<$> da Control.Applicative, ed è lo stesso che fmap)

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

L'unico fastidio è l'aspersione gratuito di lift s, ma ci sono modi per sbarazzarsi di quelli.

+1

Una volta che l'app è stata completata, devo premere di nuovo i libri di Haskell. Certo, ho sentito parlare di cose come Applicative e Functional, ma non li ho mai usati. Se più conoscenza può rendere il mio codice più sexy allora sono tutto per questo. –

Problemi correlati