场景:我有一个解释器,可以从 AST 自下而上构建值。某些节点带有权限——附加的 bool 表达式。权限失败应该传播,但是如果 AST 中上面的节点具有权限,则成功可以恢复计算并停止错误的传播。
起初我认为 Error MyError MyValue
monad 就足够了:MyError
的成员之一可以是 PermError
,我可以如果第二次检查成功,则使用 catchError
从 PermError
中恢复。然而,当我到达处理程序时,MyValue
已经消失了。我想最终可能有一种方法让 PermError 携带 MyValue
字段,以便处理程序可以恢复它,但它可能会很丑陋,并且在每个步骤中检查异常会破坏一个概念异常发生。
我正在尝试考虑另一种抽象。基本上我必须返回一个数据类型 Either AllErrorsExceptPermError (Maybe PermError, MyValue)
或更简单的 (Maybe AllErrors, MyValue)
(其他错误是不可恢复的并且非常适合错误单子(monad))好吧),我正在寻找一些可以让我免于处理元组的东西,因为操作的链接方式似乎有一个共同的模式。我的 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"
errors 已被简化为 T,并且 instance
行可能存在语法错误,但您应该明白这一点。这有道理吗?
最佳答案
我认为您可以使用 State
monad 进行权限和值计算,并将其包装在 ErrorT
monad 转换器中来处理错误。下面是一个展示这个想法的例子,这里的计算是对一个列表进行求和,权限是列表中偶数的数量和错误条件 em> 是当我们在列表中看到 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)
关于haskell - 我如何在 haskell 中抽象这个模式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17668467/