在Haskell中使用Either Monad进行错误处理

6
我有一个函数,用于检查一个类型是否是另一个类型的子类型:
st :: Monad m => Map String Type  -- ^type environment
   -> Set (Type, Type) -- ^assumed subtypes
   -> (Type, Type) -- ^we are checking if lhs <: rhs      
   -> m (Set (Type, Type))

我想进行错误处理。我有以下定义:

instance Monad (Either String) where
  return v = Right v
  fail s = Left s
  (Left s) >>= _ = Left s
  (Right v) >>= f = f v

有时我可以通过将st的结果视为Either来处理错误。例如,下面的函数可以正常工作,并获取调用st中“fail”产生的消息:

isSubType env cs t1 t2 = result where
  result = case st env (S.empty) (t1, t2) of
    Left msg -> Left msg
    Right rel -> Right ()

现在,我在 st 中,并且想要递归地调用它。由于某些原因,下面的代码嵌套在 st 中:
  let do_t1 rel t1 = case st env rel (t1, t2) of
        Left msg -> fail $ printf "type %s in the union is not a subtype\
                           \ of the rhs, %s, because: %s" (renderType t1)
                           (renderType t2) (show msg)
        Right rel -> return rel

不进行类型检查,但会出现以下错误:
 No instance for (Monad (Either t))
      arising from a use of `st'
                   at src/TypedJavaScript/Types.hs:386:24-42
    Possible fix: add an instance declaration for (Monad (Either t))

为什么在'st'之外将st的结果处理为Either是有效的,但在其中不起作用?我该如何更改代码,使其在其中也能起作用?


3
你似乎在重新实现 Control.Monad.Error 模块? - ephemient
1个回答

5

我认为问题在于你调用了show msg,而应该只使用msg。因此,编译器无法推断出你的意思是Either String;它只知道你有一个满足Show t约束条件的Either t。将show msg替换为msg应该可以解决这个问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接