stu*_*ith 13 error-handling monads haskell
我试图了解Haskell中的错误处理.我发现文章" 8种方法来报告Haskell中的错误 ",但我很困惑为什么Maybe和Either表现不同.
例如:
import Control.Monad.Error
myDiv :: (Monad m) => Float -> Float -> m Float
myDiv x 0 = fail "My divison by zero"
myDiv x y = return (x / y)
testMyDiv1 :: Float -> Float -> String
testMyDiv1 x y =
case myDiv x y of
Left e -> e
Right r -> show r
testMyDiv2 :: Float -> Float -> String
testMyDiv2 x y =
case myDiv x y of
Nothing -> "An error"
Just r -> show r
Run Code Online (Sandbox Code Playgroud)
调用testMyDiv2 1 0给出结果"An error",但调用testMyDiv1 1 0给出:
"*** Exception: My divison by zero
Run Code Online (Sandbox Code Playgroud)
(注意缺少结束引用,表明这不是字符串而是例外).
是什么赋予了?
mok*_*kus 15
简短的回答是Haskell中的Monad类将fail操作添加到monad的原始数学概念中,这使得如何将Either类型转换为(Haskell)有点争议Monad,因为有很多方法可以做到这一点.
有几种实现浮动可以做不同的事情.我所知道的3种基本方法是:
fail = Left.这似乎是大多数人所期望的,但它实际上不能在严格的Haskell 98中完成.实例必须声明为instance Monad (Either String),这在H98下是不合法的,因为它提到了一个Eithers参数的特定类型(在GHC,FlexibleInstances扩展将导致编译器接受它).fail,使用刚调用的默认实现error.这就是你的例子中发生的事情.这个版本具有兼容H98的优点,但缺点是对用户来说相当令人惊讶(令人惊讶的是在运行时).fail实现调用其他类将String转换为任何类型.这是在MTL的Control.Monad.Error模块中完成的,该模块声明instance Error e => Monad (Either e).在这个实现中,fail msg = Left (strMsg msg).这个也是合法的H98,并且偶尔会让用户感到惊讶,因为它引入了另一个类型.与上一个例子相反,惊喜发生在编译时.