Haskell 需要MonadPlus(ST a)实例
我正在读这篇文章,但我没有理解最终实现的细节。特别是第4节中介绍的回溯状态转换器。出于某种原因,我不知道,GHC认为我需要一个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
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
是typeclassMonadPlus
的成员。特别是
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
forST
看起来是可交换的。不过,这只是一个纪律问题,而不是ST
是否真的是一个行为良好的MonadPlus
实例。