我重新访问了Haskell,并构建了一个玩具编程语言解析器/解释器。使用Parsec进行lexing和解析以及单独的解释器。我正在解决一些问题,将解析器的结果提供给我的解释器,并处理解释器和解析器的潜在错误。我最终得到这样的东西:
main = do
fname <- getArgs
input <- readFile (head fname)
case lparse (head fname) input of
Left msg -> putStrLn $ show msg
Right p -> case intrp p of
Left msg -> putStrLn $ show msg
Right r -> putStrLn $ show r
这个看起来很漂亮。我的问题是,lparse
返回Either ParseError [(String, Stmt)]
而itrp
返回类型Either ItrpError Stmt
,因此我很难从Right
结果中获取ParseError
结果解析器解析器,同时保释并打印可能的IntrpError
或main = do
fname <- getArgs
input <- readFile (head fname)
let prog = lparse (head fname) input
(putStrLn . show) (intrp <$> prog)
。
最接近我想要的是这样的
Lefts
但这不会令人惊讶地产生嵌套的Either,也不会打印得很漂亮。
那么有没有任何好的Haskell思想方法来做这个线程从一个计算到另一个计算并以一种很好的方式处理错误(lparse
)而没有嵌套案例?
修改
添加itrp
和lparse :: Text.Parsec.Pos.SourceName -> String -> Either Text.Parsec.Error.ParseError [([Char], Stmt)]
intrp :: [([Char], Stmt)] -> Either IntrpError Stmt
service = discovery.build('gmail', 'v1', http=http)
答案 0 :(得分:4)
虽然不完美,但我会创建一个辅助函数,用于将Show
中任何Either
错误的错误嵌入到MonadError
中:
{-# LANGUAGE FlexibleContexts #-}
import Control.Monad.Except
strErr :: (MonadError String m, Show e) => Either e a -> m a
strErr = either (throwError . show) return
然后,如果您的计算可能会因错误而失败,例如
someFn :: ExceptT String IO ()
someFn = strErr (Left 42)
您可以将其运行(将错误打印到 stdout )
main :: IO ()
main = runExceptT someFn >>= either putStrLn return
在你的情况下,它就像是
main = either putStrLn return <=< runExceptT $ do
fname <- liftIO getArgs
input <- liftIO $ readFile (head fname)
prog <- strErr $ lparse (head fname) input
r <- strErr $ interp prog
print r
答案 1 :(得分:2)
好吧,如果你想连接成功的计算,你总是可以使用>>=
来做到这一点。例如在你的情况下:
lparse (head fname) input >>= intrp
如果你想打印出你的错误信息,你可以使用带有两个处理函数的either
类,一个用于Left a
的情况(你的情况是错误的)和另一个对于Right b
(在您的情况下是成功的事情)。一个例子:
either (putStrLn . show) (putStrLn . show) (lparse (head fname) input >>= intrp)
如果您的链条中的任何内容失败(您的monadic链的任何步骤变为Left a
)它就会停止,并且可以在上述情况下打印出错误消息。