2012-06-03 14 views
15

Ich habe mir einen Tag lang über diesen Kopf gekratzt.Monadische Ausdrücke in conditionals - GHC kompiliert, cabal lehnt ab

Ich habe ein paar Funktionen in meinem Code, der wie folgt aussehen:

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 wird geladen und dies ohne Probleme interaktiv ausführen, und ghc es glücklich kompilieren. Ausführen dieses durch Kabalen, gibt mir aber diese:

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? 

Und was auch immer diese -XDoAndIfThenElse Option ist, kann ich nicht eine Spur davon überall in jeder Dokumentation zu finden scheinen. Warum ist cabal (oder ist das ghc an diesem Punkt?) Schrie mich an für die Verwendung von Semikolons, die IT dort an erster Stelle gesetzt? Oder verwenden monadische Ausdrücke in if-then-else-Anweisungen nur eine schlechte Idee?

Beachten Sie, dass Kabale darüber gar nicht beschweren:

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

... außer dies ist hässlich wie die Hölle, und ich würde nie wollen, dies in meinem Code setzen. Kann mir jemand sagen, was los ist? Bitte und danke im Voraus.

Antwort

27

der „richtige“ Weg if -expressions in einem do -block einzurücken ist, um die else und then Linien weiter als die if, wie diese einrücken.

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

Dies liegt daran, Linien mit der gleichen Menge an Einbuchtung in einem do Block normalerweise als separate Anweisungen behandelt.

Es gibt jedoch eine Erweiterung namens DoAndIfThenElse, mit der Sie es so schreiben können, wie Sie es getan haben. Diese Erweiterung wurde in Haskell 2010 zum Standard gemacht, weshalb GHC sie standardmäßig aktiviert.

Cabal neigt dazu, dass Sie expliziter über diese Dinge sind, so dass Sie es in Cabal verwenden müssen, entweder in Ihrer .cabal Datei oder fügen Sie {-# LANGUAGE DoAndIfThenElse #-} an der Spitze des Moduls.

+3

Danke, ich füge nur die Einzüge hinzu, wenn nötig! –

6

Dies ist keine direkte Antwort auf Ihre Frage, aber Sie können die if-Anweisung beseitigen, indem Sie MaybeT ausnutzen. Auch foo >>= return . bar ist das gleiche wie bar <$> foo. (<$> ist von Control.Applicative, und ist die gleiche wie fmap)

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

Das einzige Ärgernis die unentgeltliche Prise lift s ist, aber es gibt Möglichkeiten, von denen loszuwerden.

+1

Sobald diese App fertig ist, muss ich die Haskell-Bücher wieder treffen. Sicher habe ich von Dingen wie Applicative und Functors gehört, aber ich habe sie nie benutzt. Wenn mehr Wissen meinen Code sexier machen kann, dann bin ich dafür. –

Verwandte Themen