2012-01-23 17 views
5

No entiendo por qué este código se activa solo una vez y luego sale? en Ghci puedo responder solo al primer ciclo, entonces parece que la variable cont se configura como falsa y no tengo el mensaje para responder.Bucle con StateT: ¿Por qué este bucle no se repite?

El resultado es:

*Main> testLoop1 td10 
test 
Do you want to continue? (y/N) 
y 
we continue 
test 
Do you want to continue? (y/N) 
We stop 

código:

type TDeckSTIO = StateT TableDecks IO 

continue = do 
putStrLn "Do you want to continue? (y/N)" 
c <- getChar 
return $ c == 'y' 


loop1 :: TDeckSTIO() 
loop1 = do 
    liftIO $ putStrLn "test" 
    cont<- liftIO continue 
    if cont 
    then do 
     liftIO $ putStrLn "we continue" 
     liftIO $ testLoop1 td 

    else liftIO $ putStrLn "We stop" 

testLoop1 td = runStateT (loop1) td >> return() 

Respuesta

15

El problema es que cuando se escribe y y pulsa enter, que en realidad es escribir dos caracteres: 'y' sí, y el carácter de nueva línea que se envía al presionar la tecla de retorno. La primera vez, el ciclo ve el 'y', pero la próxima vez, ve el '\n', y dado que '\n' no es 'y', sale.

Puede hacerlo hSetBuffering stdin NoBuffering antes de entrar en el bucle (necesitará importar System.IO), que le permitirá procesar caracteres sin esperar a una nueva línea, o específicamente procesar líneas a la vez:

continue = do 
    putStrLn "Do you want to continue? (y/N)" 
    s <- getLine 
    return $ s == "y" 

Por cierto, en lugar de escribir liftIO $ testLoop1 td, puede permanecer en la misma mónada de estado: puede reemplazarlo por loop1 y funcionará exactamente igual.

Además, testLoop1 es mejor escribir como:

testLoop1 = evalStateT loop1 

evalStateT es como runStateT, pero no incluye el estado final, por lo que no hay que descartar explícitamente el valor con >> return().

+0

Gracias exactamente lo que quería y más. Estaba en el camino encontrando cuando acabo de cambiar el código y agregué una impresión que muestra el '\ n'. Gracias por la sugerencia de liftIO $ testLoop1 td -> loop1. Esa fue una de mis pruebas previas y me preguntaba cuál de esos dos códigos reemplazar. Y buen punto con evalState. Esa fue mi primera incursión con statetransformer y IO. –

Cuestiones relacionadas