2016-04-12 18 views
1

Ich muss ein sehr kleines Spiel in Haskell für einen Kurs machen, dem ich folge. Also habe ich die Play-Funktion erstellt, aber jetzt habe ich Probleme, die Typ-Signatur zu ändern.Wie verwende ich die StateT Monade richtig?

play :: [[String]] -> StateT GameState IO Score 
play input = 
do 
    liftIO $ clearScreen 
    (answered, correct) <- get 
    if True 
    then 
     do 
      liftIO $ putStrLn "Well done! Your answer was correct!" 
      liftIO $ putStrLn ("So far, you answered " ++ (show answered) ++ " questions") 
      put (answered + 1, correct + 1) 
      liftIO $ 
       do 
        temp <- getLine 
        putStrLn temp 
    else 
     do 
      liftIO $ putStrLn "I'm sorry, you're wrong..." 
      put (answered + 1, correct) 
    play input 

Nun, bitte beachten Sie die if True Aussage, das ist nur zum Testen. Jetzt funktioniert diese Funktion, aber ich muss es mit einer anderen Typ-Signatur arbeiten lassen. Die Art Signatur der Funktion sollte ein Spiel sein:

play :: IO (Either ParseError [[String]]) -> StateT GameState IO Score 

Aber ich habe absolut keine Ahnung, wie dann meine StateT Monade benutzen? Wie kann ich das machen? Die IO (Either ParseError [[String]]) Monade ist ein Ergebnis der parseFromFile-Funktion aus dem missingH-Paket.

+1

Ich sehe nicht, warum Sie 'play' ändern müssen. Was immer 'parseFromFile' aufruft, sollte basierend auf diesem Ergebnis entscheiden, ob 'play' aufgerufen wird oder nicht. – chepner

+0

@chepner Ok, aber wie kann ich spielen mit dem '[[String]]' anstelle des 'IO (Entweder ParseError [[String]])'? Ich habe keinen direkten Zugriff auf die [[String]]. –

+2

Sie können 'lift :: IO (entweder ParseError [[String]]) -> StateT GameState IO (Entweder ...)' verwenden und dann monadische Bindung ('>> =' oder innerhalb eines 'do'-Blocks) verwenden dieser Wert. Sie müssen sich immer noch mit dem 'ParseError' beschäftigen - vielleicht eine Ausnahme auslösen oder Ihre Monade zu' StateT GameState (ErrorT SomeErrorType IO) '' – user2407038

Antwort

4

Der Anrufer sollte damit umgehen.

main :: IO() 
main = do 
    parsed <- parseFromFileStuff 
    case parsed of 
    Left parseerror -> handleErrorStuff 
    Right input -> evalStateT (play input) initialState 

Durch die Art und Weise zurückkehren, die Sie nie wirklich eine Punktzahl, so dass der Rückgabetyp playVoid sein sollte, nicht Score. Außerdem sollten Sie diese Rekursion verschärfen, indem Sie die letzte Zeile play entfernen, ihren Rückgabetyp auf () ändern und play input durch forever (play input) ersetzen. Oh, und du benutzt nie die Eingabe.

+0

Vielen Dank! Das funktioniert wie erwartet :) Die Eingabe wird in einer anderen Funktion verwendet, die ich in dieser Implementation nicht mitgespielt habe;) –