2012-06-03 17 views
15

Przeszedłem przez głowę nad tym dniem.Wyrażenia monadyczne w warunkach warunkowych - kompilacja GHC, odmowa cabal

Mam kilka funkcji w moim kodu, który wygląda tak:

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 będzie załadować i uruchomić ten interaktywnie bez żadnych problemów, a ghc będzie go skompilować szczęśliwie. Running to przez klika jednak daje mi to:

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? 

i cokolwiek ta opcja -XDoAndIfThenElse jest, nie wydaje się znaleźć śladu nigdzie w jakiejkolwiek dokumentacji. Dlaczego cabal (czy jest to skrót od ghc?) Krzyczy na mnie za używanie średników, które IT umieścił tam na pierwszym miejscu? Lub używa wyrażeń monadycznych w wyrażeniach if-then-else po prostu zły pomysł?

Zauważ, że kabała nie narzekać to w ogóle:

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

... oprócz tego jest brzydki jak cholera i nigdy nie chcą umieścić to w moim kodu. Czy ktoś może mi powiedzieć, co się dzieje? Proszę i dziękuję z góry.

Odpowiedz

27

„prawidłowy” sposób wcięcia if -expressions w do -blok jest wcięcie else i then linii dalej niż if, tak.

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

Wynika to linie o tej samej ilości wcięć w do bloku są zwykle traktowane jako odrębnych stwierdzeniach.

Istnieje jednak rozszerzenie o nazwie DoAndIfThenElse, które pozwoli Ci napisać to tak, jak zrobiłeś. To rozszerzenie zostało wprowadzone w standardzie w Haskell 2010, dlatego domyślnie GHC je włącza.

Cabal zazwyczaj wymaga od ciebie wyraźniejszego wyrażania swoich opinii, więc aby użyć go w Cabal, musisz o tym wspomnieć w swoim pliku .cabal lub dodać {-# LANGUAGE DoAndIfThenElse #-} na górze swojego modułu.

+3

Dzięki, dodam tylko wcięcia zgodnie z potrzebami! –

6

To nie jest bezpośrednia odpowiedź na twoje pytanie, ale możesz wyeliminować instrukcję if, korzystając z MaybeT. Ponadto, foo >>= return . bar jest taki sam jak bar <$> foo. (<$> wynosi od Control.Applicative, i jest taka sama jak fmap)

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

Jedyny kłopot jest nieodpłatne pokropienie lift s, ale istnieją sposoby, aby pozbyć się tych.

+1

Po zakończeniu tej aplikacji muszę ponownie trafić w książki Haskella. Oczywiście słyszałem o aplikacjach i funkcjach, ale nigdy ich nie używałem. Jeśli większa wiedza może sprawić, że mój kod będzie bardziej seksowny, to jestem po to. –