我有以下 monad 转换器来处理 Haskell 中的错误。
instance (Monad m, Error e) => Monad (EitherT e m) where
return = EitherT . return . return
m >>= k = EitherT $ do
a <- runEitherT m
case a of
Left l -> return (Left l)
Right r -> runEitherT (k r)
fail = EitherT . return . Left . strMsg
它工作得相当好,因为我可以Error
使用自定义类进行实例化,并且有一种非常灵活的方式来处理错误。
fail
不过,这有点傻,因为它是 type String -> EitherT e m
,并且String
限制可能是一种令人讨厌的创建错误的方式。我最终得到了很多:
instance Error BazError where
strMsg "foo" = FooError -- oh look we have no error context
strMsg "bar" = BarError -- isn't that nice
我想做的是创建一个新函数,例如fail
,它是类型a -> e
,以便我可以删除(Error e)
限制。fail
当 monad 堆栈变大时特别方便,比如当我结束时
EitherT BazError (StateT [BazWarning] IO) Foo
有没有办法创建一个fail
与限制较少的类型具有相同行为的函数?或者是fail
使用 deep haskell 暗魔法实现的?