Haskell 如何从此代码中删除'case of'?
如何重写以下代码,以便:Haskell 如何从此代码中删除'case of'?,haskell,Haskell,如何重写以下代码,以便: 使用更少的字符 最多包含一个案例。。。属于… --parseSQL::String->ParseError-SQL --evalSQL::SQL->IO(EvalError表之一) --prettyPrintTable::Table->IO() --ParseError、EvalError和Table是Show的实例 evalAndPrint::字符串->IO() evalAndPrint x= 案例解析 (左语法分析器)-> 打印分析器 (右sql)->do 结果 打
案例。。。属于…
--parseSQL::String->ParseError-SQL
--evalSQL::SQL->IO(EvalError表之一)
--prettyPrintTable::Table->IO()
--ParseError、EvalError和Table是Show的实例
evalAndPrint::字符串->IO()
evalAndPrint x=
案例解析
(左语法分析器)->
打印分析器
(右sql)->do
结果
打印错误
(右表)->do
预打印表格
putStrLn$“(“++显示(长度表)++”行)\n”
现在,让我们假设您已经将parseSQL
和evalSQL
函数概括为这些类型(稍后我们将看到如何将您的专用实现转化为通用实现,即使您无法访问它们的源代码):
然后我们可以写:
-- if we were really doing this the mtl way, we'd introduce a new
-- type class for changing error types instead of specializing to
-- ExceptT, but that's another answer
evalAndThrow :: String -> ExceptT String IO ()
evalAndThrow s = do
sql <- withExceptT show (parseSQL s)
table <- withExceptT show (evalSQL sql)
liftIO $ prettyPrintTable table
liftIO . putStrLn $ "(" ++ show (length table) ++ " lines)\n"
当然还有
ExceptT::IO(ea)->exceptteioa
<代码>例外。evalSQL也不像liftio那样具有多态性。evalSQL
,但由于我们在例外的类型上使用它,所以在这种情况下它可能并不重要。看起来像是error
、EitherT
或其他一些错误monad转换器的完美候选。您几乎可以直接使用的monad
实例来实现这一点。不幸的是,evalSQL
有点搞砸了。因此,看起来您需要EitherT
或其他什么……这也很困难,因为在每种情况下使用的两个monad实例都是不同的。第一个Orther monad实例是Orther ParseError
,第二个是Orther EvalError
。
parseSQL :: MonadError ParseError m => String -> m SQL
evalSQL :: (MonadError EvalError m, MonadIO m) => SQL -> m Table
-- if we were really doing this the mtl way, we'd introduce a new
-- type class for changing error types instead of specializing to
-- ExceptT, but that's another answer
evalAndThrow :: String -> ExceptT String IO ()
evalAndThrow s = do
sql <- withExceptT show (parseSQL s)
table <- withExceptT show (evalSQL sql)
liftIO $ prettyPrintTable table
liftIO . putStrLn $ "(" ++ show (length table) ++ " lines)\n"
evalAndPrint s = do
v <- runExceptT (evalAndThrow s)
case v of
Left err -> putStrLn err
Right _ -> return ()
-- this is a generally useful combinator
liftEither :: MonadError e m => Either e a -> m a
liftEither = either throwError return
-- this is a combinator specific to your question
liftIOEither :: (MonadError e m, MonadIO m) => IO (Either e a) -> m a
liftIOEither = join . liftIO . liftM liftEither