parseSource :: String -> Either ParserError Mod.Module
parseSource src = do
(imports, rest) <- parseImports (Lex.lexSource src)
bindings <- mapM parseBinding rest
buildModule imports bindings
我需要使上面的返回IO (Either ParserError Mod.Module)
,因为最后buildModule
语句需要执行一些IO功能(读取文件)。我遇到的问题是,当我使它成为IO函数时,我不能再进行绑定(错误的术语?)<-
操作。
使这项工作最简单的方法是什么?
答案 0 :(得分:6)
看看根据ErrorT ParseError IO定义问题。
答案 1 :(得分:3)
我找不到组合器将纯Either
计算提升到ErrorT
monad,所以我写了一个名为liftError
的组合。我用虚拟类型和实现充实了你的例子。 main
运行解析器两次,一次输入引发ParserError
,一次运行IO
副作用。要使ErrorT ParserError IO
成为Monad
,ParserError
必须是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"]