У меня проблемы с пониманием вашего вопроса.Также я не очень знаком с подсказкой.Но я попробую.
Насколько я могу судить, монада Interpreter
- это просто простая оболочка состояния вокруг IO
- она существует только для того, чтобы вы могли сказать, например.setImportsQ [...]
и последующие вычисления зависят от «настроек», которые были изменены этой функцией.Таким образом, вы хотите поделиться монадическим контекстом нескольких вычислений.Единственный способ сделать это - остаться в монаде - создать одно вычисление в Interpreter
и запустить его один раз.Вы не можете иметь «глобальную переменную», которая экранирует и повторно использует runInterpreter
.
К счастью, Interpreter
является экземпляром MonadIO
, что означает, что вы можете чередовать вычисления IO
и Interpreter
вычисления с использованием liftIO :: IO a -> Interpreter a
.По сути, вы думаете наизнанку (крайне распространенная ошибка для учащихся Haskell).Вместо использования функции в IO
, которая выполняет код в вашем интерпретаторе, используйте функцию в Interpreter
, которая выполняет код в IO
(а именно liftIO
).Например,
main = runInterpreter $ do
testHint
expr1 <- liftIO getLine
r1 <- interpret "" expr1
case r1 of
...
expr2 <- liftIO getLine
r2 <- interpret "" expr2
case r2 of
...
И вы можете легко вывести этот последний код в функцию, если вам нужно, используя всю прелесть ссылочной прозрачности!Просто вытащите его прямо.
runSession :: Interpreter ()
runSession = do
expr1 <- liftIO getLine
r1 <- interpret "" expr1
case interpret expr1 of
...
main = runInterpreter $ do
testHint
runSession
Имеет ли это смысл?Ваша вся программа является вычислением Interpreter
, и только в последнюю минуту вы извлекаете ее в IO
.
(что означает не , что означает, чтокаждая написанная вами функция должна быть в монаде Interpreter
. Далеко от нее! Как обычно, используйте Interpreter
по краям вашей программы и держите ядро чисто функциональным. Interpreter
- это новый IO
).