【问题标题】:Using Logic monad to backtrack upon exception thrown with ExceptT使用 Logic monad 回溯使用 exceptT 引发的异常
【发布时间】:2021-01-07 20:28:48
【问题描述】:

我想使用Logic monad 来确保抛出错误的代码(在包括ExcepT 的monad 堆栈中)在抛出错误时回溯。这是一个简单的例子:

newtype FooT m a = FooT { unFooT :: ExceptT String m a }
  deriving (Functor, Applicative, Monad, MonadTrans, MonadError String, MonadFail)
 

foo :: FooT Logic String
foo = do
  let validate s = if s == "cf" then return s else throwError "err"
  let go = do
        first <- msum (map return ['a', 'b', 'c'])     
        second <- msum (map return ['d', 'e', 'f'])
        traceM $ "Guess: " ++ [first, second]
        validate [first, second]
  go `catchError` const mzero

testfoo :: IO ()
testfoo = do
  let r = observe $ runExceptT $ unFooT foo
  case r of
    Left e -> print $ "Error: " ++ e
    Right s -> print $ "Result: " ++ 

这不会回溯;它不会产生任何结果。 我可以通过取消选择操作使其回溯(即,使用lift (msum ...) 而不是现在的普通msum 调用)。 但是,出于多种原因,我希望能够在 ExceptT monad 中编写代码,并且基本上只是将 MonadPlus 实例从 Logic monad 提升到转换后的版本。 我试图在这里编写一个自定义的MonadPlus 实例来完成此操作:

instance MonadPlus m => MonadPlus (FooT m) where
  mzero = lift mzero
  mplus (FooT a) (FooT b) = lift $ do
    ea <- runExceptT a
    case ea of
      Left _ -> do
        eb <- runExceptT b
        case eb of
          Left _ -> mzero
          Right y -> return y
      Right x -> do
        eb <- runExceptT b
        case eb of
          Left _ -> return x
          Right y -> return x `mplus` return y

同样的代码也适用于Alternative 实例。但是,这实际上并没有帮助。它仍然没有回溯。这个实例有问题吗?有没有更好的方法来解决这个问题?我在尝试做一些没有意义的事情吗?在一天结束时,我总是可以举起所有东西,但宁愿避免这样做。

编辑: 又闹了一些。如果我使用mplus,我上面的MonadPlus 实例可以工作,但是如果我像上面那样使用msumnot 工作......

【问题讨论】:

    标签: haskell search alternative-functor monadplus


    【解决方案1】:

    使用MonadPlus/Alternative的这个实例:

    instance (Alternative m, Monad m) => Alternative (FooT m) where
      empty = FooT (ExceptT empty)
      FooT (ExceptT a) <|> FooT (ExceptT b) = FooT (ExceptT (a <|> b))
    

    注意:AlternativeMonadPlus 是多余的,因此只实现 Alternative 并使用 Data.Foldable.asum 而不是 msum 会更简单。

    您实现的那个与ExceptT 上已经存在的那个差别不大,并且没有真正使用Alternative m 实例。确保使用(&lt;|&gt;) 专用于m 以从回溯中受益。

    【讨论】:

      猜你喜欢
      • 2015-08-14
      • 2012-07-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-03
      • 1970-01-01
      • 2014-06-02
      相关资源
      最近更新 更多