简体   繁体   English

将monadic函数转换为IO monadic函数

[英]Converting a monadic function to an IO monadic function

parseSource :: String -> Either ParserError Mod.Module
parseSource src = do
    (imports, rest) <- parseImports (Lex.lexSource src)
    bindings <- mapM parseBinding rest
    buildModule imports bindings

I need to make the above return an IO (Either ParserError Mod.Module) as the buildModule statement at the end will need to perform some IO functions (reading files). 我需要在上面返回一个IO (Either ParserError Mod.Module)因为最后的buildModule语句需要执行一些IO功能(读取文件)。 The problem i have is that when i make it an IO function, i can no longer do the bind(wrong term?) <- operations. 我遇到的问题是,当我使它成为IO函数时,我不能再进行绑定(错误的术语?) <-操作。

What is the simplest way to make this work? 使这项工作最简单的方法是什么?

看一下根据ErrorT ParseError IO定义问题。

I couldn't find a combinator to lift a pure Either computation into the ErrorT monad, so I wrote one called liftError . 我找不到一个组合器来将纯Either计算提升到ErrorT monad中,所以我写了一个名为liftError I fleshed out your example with dummy types and implementations. 我用虚拟类型和实现充实了你的例子。 The main runs the parser twice, once with input that throws a ParserError , and once which succeeds with an IO side-effect. main运行解析器两次,一次输入抛出ParserError ,一次运行IO副作用。 In order for ErrorT ParserError IO to be a Monad , ParserError must be an instance of Error (so that it is possible to implement fail ). 为了使ErrorT ParserError IO成为MonadParserError必须是Error一个实例(这样才有可能实现fail )。

import Control.Monad.Error

type ParserMonad = ErrorT ParserError IO

data ParserError = ParserError1 | ParserError2 | ParserError3
                   deriving(Show)
data Module = Module
              deriving(Show)
data Import = Import
              deriving(Show)
data Binding = Binding
               deriving(Show)

instance Error ParserError where
    noMsg = undefined

-- lift a pure Either into the ErrorT monad
liftError :: Monad m => Either e a -> ErrorT e m a
liftError = ErrorT . return

parseSource :: String -> ParserMonad Module
parseSource src = do
    (imports, rest) <- liftError $ parseImports (lexSource src)
    bindings <- liftError $ mapM parseBinding rest
    buildModule imports bindings

lexSource :: String -> [String]
lexSource = return

parseImports :: [String] -> Either ParserError ([Import], [String])
parseImports toks = do{ when (null toks) $ throwError ParserError1
                      ; return ([Import], toks)
                      }

parseBinding :: String -> Either ParserError Binding
parseBinding b = do{ when (b == "hello") $ throwError ParserError2
                   ; return Binding
                   }

buildModule :: [Import] -> [Binding] -> ParserMonad Module
buildModule i b = do{ liftIO $ print "hello"
                    ; when (null b) $ throwError ParserError3
                    ; return Module
                    }

main = mapM (runErrorT . parseSource) ["hello", "world"]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM