data Console a
= PutStrLn String a
| GetLine (String -> a)
deriving (Functor)
type ConsoleM = Free Console
runConsole :: Console (IO a) -> IO a
runConsole cmd =
case cmd of
(PutStrLn s next) -> do
putStrLn s
next
(GetLine nextF) -> do
s <- getLine
nextF s
runConsoleM :: ConsoleM a -> IO a
runConsoleM = iterM runConsole
consolePutStrLn :: String -> ConsoleM ()
consolePutStrLn str = liftF $ PutStrLn str ()
consoleGetLine :: ConsoleM String
consoleGetLine = liftF $ GetLine id
data File a
= ReadFile FilePath (String -> a)
| WriteFile FilePath String a
deriving (Functor)
type FileM = Free File
runFile :: File (MaybeT IO a) -> MaybeT IO a
runFile cmd = case cmd of
ReadFile path next -> do
fileData <- safeReadFile path
next fileData
WriteFile path fileData next -> do
safeWriteFile path fileData
next
runFileM :: FileM a -> MaybeT IO a
runFileM = iterM runFile
rightToMaybe :: Either a b -> Maybe b
rightToMaybe = either (const Nothing) Just
safeReadFile :: FilePath -> MaybeT IO String
safeReadFile path =
MaybeT $ rightToMaybe <$> (try $ readFile path :: IO (Either IOException String))
safeWriteFile :: FilePath -> String -> MaybeT IO ()
safeWriteFile path fileData =
MaybeT $ rightToMaybe <$> (try $ writeFile path fileData :: IO (Either IOException ()))
fileReadFile :: FilePath -> FileM String
fileReadFile path = liftF $ ReadFile path id
fileWriteFile :: FilePath -> String -> FileM ()
fileWriteFile path fileData = liftF $ WriteFile path fileData ()
data Program a = File (File a) | Console (Console a)
deriving (Functor)
type ProgramM = Free Program
runProgram :: Program (MaybeT IO a) -> MaybeT IO a
runProgram cmd = case cmd of
File cmd' ->
runFile cmd'
Console cmd' ->
-- ????
runProgramM :: ProgramM a -> MaybeT IO a
runProgramM = iterM runProgram
我想撰寫兩個免費的 monadConsoleM和FileM. 所以,我做了組合函子Program。然后我開始撰寫解釋器函式runProgram,但我無法定義函式。因為runConsole和MaybeT IO a型別不匹配。如何將 runConsole 函式提升runConsole :: Console (IO a) -> IO a為具有型別Console (MaybeT IO a) -> MaybeT IO a?
(我想用 Free monads 來實作這個程式,而不是 Eff monad。)
uj5u.com熱心網友回復:
現在你有cmd'type Console (MaybeT IO a),并且想把它傳遞給一個函式Console (IO a)。您可以做的第一件事是在MaybeT里面運行 monadConsole并獲取Console (IO (Maybe a)). 您可以通過fmapping來執行此操作runMaybeT。
一旦你得到Console (IO (Maybe a)),你可以將它傳遞給runConsole并得到IO (Maybe a)。現在,您可以將其提升到MaybeT IO a使用MaybeT.
所以它會是這樣的。
runProgram :: Program (MaybeT IO a) -> MaybeT IO a
runProgram cmd = case cmd of
File cmd' ->
runFile cmd'
Console cmd' ->
MaybeT $ runConsole $ fmap runMaybeT cmd'
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/434065.html
