我有一个RWST
Monad,并且有一些泛型函数可以与Writer
部分进行交互。
作为参考,RWST
是这样的:
newtype RWST r w s m a = RWST {runRWST :: r -> s -> m (a, s, w)}
instance (Monoid w, Monad m) => Monad (RWST r w s m)
instance Functor m => Functor (RWST r w s m)
instance (Monoid w, MonadFix m) => MonadFix (RWST r w s m)
instance (Monoid w, MonadPlus m) => MonadPlus (RWST r w s m)
instance Monoid w => MonadTrans (RWST r w s)
instance (Monoid w, MonadIO m) => MonadIO (RWST r w s m)
instance (Monoid w, Monad m) => MonadWriter w (RWST r w s m)
instance (Monad m, Monoid w) => MonadState s (RWST r w s m)
instance (Monad m, Monoid w) => MonadReader r (RWST r w s m)
instance (Monoid w, Monad m) => MonadRWS r w s (RWST r w s m)
所以我有一个像这样的数据Definition
:
type Definition = RWS SapphireReader DefWriter DefState
DefWriter
只是type DefWriter = Seq Error
(错误由我定义,而不是Control.Monad.Error
)。
我有一个工作职能:
tellPError :: Position -> ParseError -> Definition ()
tellPError posn err = tell (singleton $ PError posn err)
现在我需要一个新的RWST并希望拥有泛型 tellPError
,我尝试删除签名,在 ghci 中加载文件并执行{{ 1}}。
:t tellPError
我尝试在代码中给我的函数签名,它不会编译:
λ :t tellPError
tellPError :: MonadWriter (Seq Error.Error) m => Position -> ParseError -> m ()
我真的需要这面旗帜吗?我尝试了它,它确实编译但不起作用。
答案 0 :(得分:2)
问题在于,根据Haskell的2010年报告部分4.1.2和4.1.3,类约束必须采用以下形式:
class → qtycls tyvar
| qtycls ( tyvar atype1 … atypen ) (n ≥ 1)
qtycls
是一个类名,tyvar
是一个类型变量,而atype
基本上几乎都是任何类型。但请注意,这两个规则的格式均为qtycls (? tyvar ...
。
但该签名包含约束:
MonadWriter (Seq Error.Error) m
其形式如下:
qtycls (gtycon1 gtycon2) tyvar
因此错误:gtycon1
s应该是类型变量,而不是类型构造函数。
为了表达该约束,您必须使用-XFlexibleContexts
扩展名。
另一种方法是通过指定所需的monad m
来消除约束,从而减少多态性。
答案 1 :(得分:0)
好的,我现在一直在关注这个问题,并提出了在RWS
右侧指定=>
的想法,这似乎可以解决问题:
tellPError :: Position -> ParseError -> RWS r (Seq Error) s ()
tellPError posn err = tell (singleton $ PError posn err)
编译并运用它的方式!