3

场景:我有一个解释器,它从 AST 自下而上构建值。某些节点带有权限——额外的布尔表达式。权限失败应该传播,但如果 AST 中的上述节点带有权限,则成功可以恢复计算并停止错误传播。

起初我认为Error MyError MyValuemonad 就足够了:其中一个成员MyErrorcould be ,如果第二次检查成功PermError,我可以使用它catchError来恢复。PermError但是,MyValue当我到达处理程序时,它已经消失了。我想最终可能会有一种方法让 PermError 携带一个MyValue字段,以便处理程序可以恢复它,但它可能会很丑陋,并且在每一步检查异常都会破坏异常发生的概念。

我正在尝试考虑另一种抽象。基本上我必须返回一个数据类型Either AllErrorsExceptPermError (Maybe PermError, MyValue)或更简单(Maybe AllErrors, MyValue)(其他错误是不可恢复的并且非常适合错误单子)并且我正在寻找可以让我免于处理元组的东西,因为似乎有一个常见的模式操作是如何链接的。我的haskell知识只到此为止。在这种情况下,你将如何使用 haskell 来发挥你的优势?

当我写这篇文章时,我想到了一个想法(SO 是一个花哨的橡皮鸭):一个在内部处理类型 (a, b) 的 Monad(并最终在 monadic 计算终止时返回它,必须有某种runMyMonad),但让我尽可能直接使用类型 b。就像是

data T = Pass | Fail | Nothing
instance Monad (T , b) where
  return v = (Nothing, v)
  (Pass, v) >>= g = let (r', v') = g v in (if r' == Fail then Fail else Pass, v')
  (Fail, v) >>= g = let (r', v') = g v in (if r' == Pass then Pass else Fail, v')
  (Nothing, _) >>= g = error "This should not have been propagated, all chains should start with Pass or Fail"

错误已被简化为 T,并且该instance行可能有语法错误,但您应该明白了。这有意义吗?

4

1 回答 1

2

我认为您可以使用Statemonad 进行权限和值计算,并将其包装在ErrorTmonad 转换器中以处理错误。下面是一个展示这个想法的例子,这里的计算是总结一个列表,权限是列表中偶数的个数,错误条件是我们在列表中看到 0。

import Control.Monad.Error
import Control.Monad.State

data ZeroError = ZeroError String
              deriving (Show)

instance Error ZeroError where


fun :: [Int] -> ErrorT ZeroError (State Int) Int
fun [] = return 0
fun (0:xs) = throwError $ ZeroError "Zero found"
fun (x:xs) = do
  i <- get
  put $ (if even(x) then i+1 else i)
  z <- fun xs
  return $ x+z


main = f $ runState (runErrorT $ fun [1,2,4,5,10]) 0
       where
         f (Left e,evens) = putStr $ show e
         f (Right r,evens) = putStr $ show (r,evens)
于 2013-07-16T10:33:09.297 回答