像 lift 这样的多态函数的类型约束
Type constraints for polymorphic functions like lift
所以我有这个代码
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
import MonadA
data A = A
newtype MonadA a => MyStateT a b { runMyStateT :: StateT A a b }
deriving (Functor, Applicative, Monad, MonadIO, MonadState A)
instance MonadTrans MyStateT where
lift = MyStateT . lift
编译器抱怨它无法证明 lift
签名中的 m
是 MonadA
类型,或者这就是我阅读这些神秘错误消息的方式。
Could not deduce (MonadA m) arising from a use of `MyStateT'
from the context (Monad m)
bound by the type signature for
lift :: Monad m => m a -> MyStateT m a
有办法解决这个问题吗?我想我需要约束才能实例化如下:
instance MonadA a => MonadA (MyStateT a) where
f = MyStateT . lift . f
f
的这种实现是否也有效? (由于上述错误,我没有走那么远)。我希望右侧的 f
在内部 monad a
.
上解析为 f
编辑:它确实有助于删除 newtype MonadA a => MyStateT ...
中的类型约束以避免我提到的确切错误。然而,还有另一个错误,我之前将其归因于同一件事,请考虑上面示例代码的延续(某些部分重复,现在没有类型限制):
class MonadB m where
fB :: m ()
newtype MyStateT m a = MyStateT { runMyStateT :: StateT A m a}
deriving (... MonadState A ...)
instance MonadTrans MyStateT where
lift = MyStateT . lift
instance MonadA a => MonadA (MyStateT a) where
f = lift . f
instance MonadA a => MonadB (MyStateT a) where
fB = lift (modify (...))
错误是
Could not deduce (a ~ StateT A m0) from context (MonadA (MyStateT a), MonadA a)
在执行fB
。早些时候我尝试 class MonadA m => MonadB m
无济于事。将 a
与 StateT A m
匹配甚至没有意义。由于 MyStateT
是 MonadState A
的一个实例,它应该可以工作,不是吗?
编辑:
好的,成功了:
fB = MyStateT (modify ...)
愚蠢的我。
解决方案是从 MyStateT
定义中删除约束:
newtype MyStateT a b { runMyStateT :: StateT A a b }
deriving (Functor, Applicative, Monad, MonadIO, MonadState A)
数据类型约束基本上是无用的,因为您无论如何都需要将它们放在函数签名中。因此,该功能实际上是 deprecated.
I think I need the constraint to be able to instantiate as follows:
不是真的; instance MonadA a => MonadA (MyStateT a)
没有它也能正常工作。
Also would such an implementation of f
work?
会的。请注意,当您为 MyStateT
提供了一个 MonadTrans
实例时,您实际上不需要明确地用 MyStateT
包装:
instance MonadA a => MonadA (MyStateT a) where
f = lift . f
所以我有这个代码
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
import MonadA
data A = A
newtype MonadA a => MyStateT a b { runMyStateT :: StateT A a b }
deriving (Functor, Applicative, Monad, MonadIO, MonadState A)
instance MonadTrans MyStateT where
lift = MyStateT . lift
编译器抱怨它无法证明 lift
签名中的 m
是 MonadA
类型,或者这就是我阅读这些神秘错误消息的方式。
Could not deduce (MonadA m) arising from a use of `MyStateT'
from the context (Monad m)
bound by the type signature for
lift :: Monad m => m a -> MyStateT m a
有办法解决这个问题吗?我想我需要约束才能实例化如下:
instance MonadA a => MonadA (MyStateT a) where
f = MyStateT . lift . f
f
的这种实现是否也有效? (由于上述错误,我没有走那么远)。我希望右侧的 f
在内部 monad a
.
f
编辑:它确实有助于删除 newtype MonadA a => MyStateT ...
中的类型约束以避免我提到的确切错误。然而,还有另一个错误,我之前将其归因于同一件事,请考虑上面示例代码的延续(某些部分重复,现在没有类型限制):
class MonadB m where
fB :: m ()
newtype MyStateT m a = MyStateT { runMyStateT :: StateT A m a}
deriving (... MonadState A ...)
instance MonadTrans MyStateT where
lift = MyStateT . lift
instance MonadA a => MonadA (MyStateT a) where
f = lift . f
instance MonadA a => MonadB (MyStateT a) where
fB = lift (modify (...))
错误是
Could not deduce (a ~ StateT A m0) from context (MonadA (MyStateT a), MonadA a)
在执行fB
。早些时候我尝试 class MonadA m => MonadB m
无济于事。将 a
与 StateT A m
匹配甚至没有意义。由于 MyStateT
是 MonadState A
的一个实例,它应该可以工作,不是吗?
编辑:
好的,成功了:
fB = MyStateT (modify ...)
愚蠢的我。
解决方案是从 MyStateT
定义中删除约束:
newtype MyStateT a b { runMyStateT :: StateT A a b }
deriving (Functor, Applicative, Monad, MonadIO, MonadState A)
数据类型约束基本上是无用的,因为您无论如何都需要将它们放在函数签名中。因此,该功能实际上是 deprecated.
I think I need the constraint to be able to instantiate as follows:
不是真的; instance MonadA a => MonadA (MyStateT a)
没有它也能正常工作。
Also would such an implementation of
f
work?
会的。请注意,当您为 MyStateT
提供了一个 MonadTrans
实例时,您实际上不需要明确地用 MyStateT
包装:
instance MonadA a => MonadA (MyStateT a) where
f = lift . f