将 Monadic 函数转换为 IO Monadic 函数

发布于 2024-12-09 09:53:39 字数 417 浏览 0 评论 0原文

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 函数时,我无法再执行绑定(错误的术语?)<- 操作。

完成这项工作的最简单方法是什么?

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). The problem i have is that when i make it an IO function, i can no longer do the bind(wrong term?) <- operations.

What is the simplest way to make this work?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

空心空情空意 2024-12-16 09:53:39

看看根据 ErrorT ParseError IO。

Take a look at defining your problem in terms of ErrorT ParseError IO.

笑,眼淚并存 2024-12-16 09:53:39

我找不到组合器将纯 Either 计算提升到 ErrorT monad 中,因此我编写了一个名为 liftError 的组合器。我用虚拟类型和实现充实了您的示例。 main 运行解析器两次,一次输入抛出 ParserError,另一次成功但产生 IO 副作用。为了使 ErrorT ParserError IO 成为 MonadParserError 必须是 Error 的实例(以便它可以实现失败)。

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"]

I couldn't find a combinator to lift a pure Either computation into the ErrorT monad, so I wrote one called 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. 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).

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"]
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文