Haskell 需要MonadPlus(ST a)实例

Haskell 需要MonadPlus(ST a)实例,haskell,monad-transformers,unification,st-monad,monadplus,Haskell,Monad Transformers,Unification,St Monad,Monadplus,我正在读这篇文章,但我没有理解最终实现的细节。特别是第4节中介绍的回溯状态转换器。出于某种原因,我不知道,GHC认为我需要一个MonadPlus实例,用于函数unify中的(ST a),如下所示: newtype BackT m a = BT { run :: forall b . (a -> m [b]) -> m [b] } instance (Monad m) => Monad (BackT m) where return a = BT (\k -> k a

我正在读这篇文章,但我没有理解最终实现的细节。特别是第4节中介绍的回溯状态转换器。出于某种原因,我不知道,GHC认为我需要一个
MonadPlus
实例,用于函数
unify
中的
(ST a)
,如下所示:

newtype BackT m a = BT { run :: forall b . (a -> m [b]) -> m [b] }

instance (Monad m) => Monad (BackT m) where
 return a   = BT (\k -> k a)
 BT m >>= f = BT (\k -> m (\a -> run (f a) k))

instance (MonadPlus m) => MonadPlus (BackT m) where 
 mzero             = BT (\s -> mzero)
 f `mplus` g = BT (\s -> (run f) s `mplus` (run g) s)

type LP a = BackT (ST a)
type LR   = STRef

type Var s a = LR s (Maybe a)   
data Atom s = VarA (Var s (Atom s)) | Atom String

class Unify b a | a -> b where
 var   :: a -> Maybe (Var b a)
 unify :: a -> a -> LP s ()

instance Unify s (Atom s) where
 var (VarA a) = Just a
 var _        = Nothing

 unify (Atom a) (Atom b) | a == b = return () -- type checks
 unify _        _                 = mzero     -- requires MonadPlus (ST a) instance
我不确定问题是什么,以及如何解决。在此之前,我的印象是我理解前面的讨论和代码,但显然我错了。如果有人能指出哪里出了问题-我是否需要
MonadPlus(sta)
实例这将非常有帮助


[编辑:澄清]我应该指出,作者似乎声称
mzero
,或
mzero
的一些变体是合适的功能。我只是不知道合适的函数是什么。我想知道的是我是否应该创建一个
MonadPlus(ST a)
实例,或者我没有使用正确的函数,并且误读了一些内容。

mzero
是typeclass
MonadPlus
的成员。特别是

mzero :: MonadPlus m => m a
用于函数
unify
的monad是
LP
,它实际上是用
ST
实例化的
BackT
。您还为
BackT
定义了
MonadPlus
的实例,该实例依赖于底层monad的实例。因为
ST
没有这样的实例,GHC会嘲笑你

这是重要的部分:

instance (MonadPlus m) => MonadPlus (BackT m) where 
  mzero             = BT (\s -> mzero)
  f `mplus` g = BT (\s -> (run f) s `mplus` (run g) s)
简单地说:这是
MonadPlus
BackT m
的一个实例,前提是
m
也是
MonadPlus
的一个实例。由于
m
ST
关联,因此
ST
需要该实例。我想知道您如何在没有委托的情况下定义
MonadPlus
的合理实例。我有一个想法:

instance MonadPlus (BackT m) where
  mzero = BT (const $ return [])
  mplus (BT f) (BT g) = BT $ \a -> do
    fs <- f a
    gs <- g a
    return $ fs ++ gs
实例MonadPlus(BackT m),其中
mzero=BT(const$return[])
mplus(BT f)(BT g)=BT$\a->do

fsBackT
MonadPlus
实例可能应该使用
[]
MonadPlus
实例,而不是
m
,如下所示:

instance (Monad m) => MonadPlus (BackT m) where 
  mzero       = BT (\_ -> return mzero)
  f `mplus` g = BT (\s -> liftM2 mplus (run f s) (run g s))

unify
的返回类型是
lps()
,或
BackT(ST a)(
)。显然,
MonadPlus
BackT m
实例需要
MonadPlus m
。你能把这个例子包括在这里吗?你是对的;我已经更新了我的帖子,加入了这些定义。有可能我误解了monad,错误地定义了bind、return、mzero或plus。这非常有效。感谢您解释问题和解决方案。小心!这个MonadPlus定义可能不是您所期望的。对分支中的
STRef
s的中间写入,如果最终失败,则不会回滚。@luqui是正确的;如果您尝试在一个分支中使用常规的
writeSTRef
,其效果将在另一个分支中看到。为了避免这种情况,请使用第4.2节中的
writeLPRef
定义。它将
BackT
延续包装在本质上是失败延续的内容中,以使
mplus
for
ST
看起来是可交换的。不过,这只是一个纪律问题,而不是
ST
是否真的是一个行为良好的
MonadPlus
实例。