我有一些函数返回Except
类型(来自transformers包),具有不同的错误类型,但都实现了类Show
。如果出现错误,我只想打印消息。
撰写/绑定它们的最佳方法是什么?
我可以在fun*
之前转换每个(=<<)
的错误类型,或者编写一个(=<<)
包装器,它接受所有可显示类型并将它们转换为String
s {{{ 1}}?),但感觉很难看。有没有更好的方法,使用类型系统,自动处理所有这些?
示例代码:
RankNTypes
答案 0 :(得分:1)
最简单的方法是创建一个新的Exception
类型(但这需要-XExistentialQuantification
)可以显示的异常。
data Exception = forall e . Show e => Exception e
然后,所有需要更改以使代码编译的都是类型签名。
funA :: String -> Except Exception String
funB :: String -> Except Exception T.Text
此外,每当您创建一个异常(上面的代码中没有示例)时,您现在需要将其包装在Exception
构造函数中。
throwsA :: String -> Except Exception String
throwsA = throwE . Exception
throwsB :: T.Text -> Except Exception T.Text
throwsB = throwE . Exception
编辑我建议您为异常制作新类型(使用适当的Show
),然后从Control.Exception派生Exception
。这是更多的开销,但如果您需要在异构异常类型之间来回切换,它可能会让您受益。这就是我的方式。
{-# LANGUAGE DeriveDataTypeable #-}
module Main where
import Data.Typeable
import Control.Exception
import Control.Monad.Trans.Except
import qualified Data.Text as T
import Control.Monad
newtype StrError = StrError String deriving (Show,Typeable)
newtype TxtError = TxtError T.Text deriving (Show,Typeable)
instance Exception StrError
instance Exception TxtError
toErr :: Exception e => Except e a -> Except SomeException a
toErr = mapExcept (either (Left . toException) Right)
funA :: String -> Except StrError String
funA = return
funB :: String -> Except TxtError T.Text
funB = return . T.pack
throwsA :: String -> Except StrError String
throwsA = throwE . StrError
throwsB :: T.Text -> Except TxtError T.Text
throwsB = throwE . TxtError
fun :: String -> IO ()
fun s = case runExcept $ (toErr . funA >=> toErr . funB) s of
Left e -> putStrLn $ displayException e
Right _ -> return ()
main :: IO ()
main = fun "foo"
答案 1 :(得分:0)
withExceptT T.unpack . funB =<< funA s
。你的节目是多余的。
使用Control.Lens
:
fun = void . _Left putStrLn . runExcept . (withExceptT T.unpack . funB <=< funA)