Мы работаем над файловой системой модели, которая использует внутреннюю монаду. У нас есть класс типа с такими операциями:
class Monad m => FS m where
isDirectory :: Path -> m Bool
children :: Path -> m [Path]
...
Мы работаем над небольшим интерактивным интерпретатором, который будет предлагать команды типа cd
, ls
, cat
и т.д. Операцию в интерпретаторе можно записать следующим образом:
fsop :: FS m => Operation -> m Response
Определения Operation
и Response
не важны; если хотите, возьмите их за строки.
Проблема, которую я пытаюсь решить, - написать цикл верхнего уровня в монаде ввода-вывода, который интерпретирует файловую систему Operation
и выводит ответы. Если бы IO был экземпляром FS (то есть, если бы мы работали напрямую с монадой IO), жизнь была бы простой: мы могли бы написать
loop :: Path -> IO ()
loop currentDir = do
op <- getLine
case read op of
ChangeDir d -> loop d -- should test 'isDirectory d', but let not
Ls -> do { files <- children currentDir
; mapM_ putStrLn files
; loop currentDir }
Exit -> return ()
Но это не то, что я хочу. Я хочу использовать Control.Monad.State
:
newtype Filesystem a = Filesystem (State (Data.Map.Map Path Contents) a)
и объявить
instance Monad Filesystem ...
instance FS Filesystem ...
Используя абстракцию FS
, я могу написать одношаговую функцию, которая должна работать с любым экземпляром, и, действительно, следующий код компилируется:
step :: FS fs => Path -> Operation -> fs (Path, Response)
step currentDir op =
case op of
ChangeDir d -> return (d, "")
Ls -> do { files <- children currentDir
; return (currentDir, unlines files) }
В этот момент я полностью застрял. Я хочу написать интерактивный цикл в монаде IO, который может читать Operation
и печатать Response
s, но который работает на государственная монада, которая не обязательно IO. (Одна из причин наличия модели, которая не находится в IO, заключается в том, что мы можем проверить свойства QuickCheck.)
Мне кажется, что это должна быть стандартная проблема - интерактивный цикл чтения-eval-print поверх абстрактной абстракции, которая не является IO
— но я должен упускать что-то потрясающе очевидное, потому что я не могу показаться чтобы понять это. Я смотрел онлайн, но не был просвещен.
Приветствуется любая помощь в написании интерактивного вычисления ввода-вывода, которое может вызывать step
.