При условии, что вы не знаете, как сохранить государство. Вот только простой пример, показывающий, как использовать StateT
для чтения символов из стандартного ввода.
Во-первых, чтобы определить функцию advanceState
как:
advanceState::StateT [Char] IO [Char]
advanceState = StateT readInput where
readInput cs = do c <- getChar
let newState = (c:cs)
return (newState, newState)
Функция, встроенная в StateT
, имеет значение readInput
, она имеет тип:
[Char]->IO ([Char], [Char])
Первый элемент пары ([Char], [Char])
является вводом того, что мы хотим, а второй элемент этого состояния - «состояние» - будет передаваться в readInput
всякий раз, когда advanceState
вызывается снова.
Теперь нижеэто пример, показывающий, как использовать advanceState
:
getChar10::StateT [Char] IO [Char]
getChar10 = do s <- advanceState
if (length s) <= 10
then getChar10
else do put []
return (reverse s)
В этом примере показано, как получить 10 символов из стандартного ввода, когда пользователь нажимает клавишу ввода, обратите внимание, что put []
сбрасывает состояние так, чтобы следующий вызовadvanceState
не будет иметь предыдущего ввода.
Наконец, мы можем поэкспериментировать с ними:
playState::IO ()
playState = print =<< evalStateT loop [] where
loop = do s1 <- getChar10
s2 <- getChar10
return (s1 ++ "::" ++ s2)
Функция playState
напечатает первые 20 символов (включая символ новой строки \n, \ r) сколько бы символов не было введено пользователем перед нажатием Enter. Если для ввода недостаточно 20 символов, playState
попросит пользователя ввести больше символов.