T1 :: (* -> *) -> * -> *
T2 :: (* -> *) -> * -> *
使用实例
instance MonadTrans T1
instance MonadTrans T2
以及一些
X :: (((* -> *) -> * -> *) -> ((* -> *) -> * -> *) -> * -> *)
例如
newtype X t1 t2 a b = X { x :: t1 (t2 a) b }
为此,我希望定义一些类似的东西。
instance (MonadTrans t1, MonadTrans t2) => MonadTrans (X t1 t2) where
lift = X . lift . lift
那么我该如何使用lift
将m a
提升为X T1 T2 m a
?
这里的问题似乎是lift
作用于一些单子Monad m => m a
,而我不能保证在中间步骤中产生它。但对我来说这很令人困惑。我正在提供一个lift
实现,因此我可以假设我有Monad m => m a
,所以我应用最右侧的lift
并得到T1 m a
,我对其一无所知,但是难道不应该暗示着T1 m
是一个Monad
吗?如果不是,为什么我不能简单地将其添加到我的实例约束中?
instance ( MonadTrans t1
, MonadTrans t2
, Monad (t2 m) ) => MonadTrans (X t1 t2) where ...
这也不起作用。我有一种直觉,认为上述内容是在说“是否应该存在
t1
,t2
和m
,使得...”,这对于证明X t1 t2
是一个变换器(适用于任何/所有的Monad m
)来说太弱了。但是对我来说仍然没有多大意义,有效的monad transformer是否能产生一个非monad,如果不能,我应该能够通过MonadTrans (X t1 t2)
的实例获得成功。有没有什么诀窍可以做到这一点,只是我无法理解,还是有一个理论限制或当前编译器支持的限制导致无法完成?
这个暗示是否对应于其他任何东西?
instance (MonadTrans t, Monad m) => Monad (t m) where
return = lift . return
a >>= b = ... # no sensible generic implementation
如果这样会重叠其他实例或无法提供特定绑定,这不是可以通过一些间接方式解决吗?将 returnT :: Monad m => a -> t m a
和 bindT :: Monad m => t m a -> (a -> t m b) -> t m b
加入到 MonadTrans
中,这样就可以编写以下代码:
instance MonadTrans (StateT s) where
lift = ...
returnT = ...
bindT = ...
...
instance (MonadTrans t, Monad m) => Monad (t m) where
return = returnT
a >>= b = a `bindT` b
这种实例目前由于重叠而无效,但如果它们可行,会有用吗?
transform
进行一些有趣的操作时,例如将单子变换器堆栈作为一等公民,你需要每个你感兴趣的变换器都有一个可用的transform
,而不仅仅是在transformers
中的那些。如果某个变换器MyT
具有transform = undefined
,那么我就不能使用ReaderT r :.: MyT
作为变换器,因为lift
和>>=
会崩溃。(transform
包含实际有用的运行时数据,即(获取)>>=
和return
的实现方式。) - Benjamin Hodgsonlift
如何依赖于transform
,特别是在当前代码中它并没有这样做。 - jakubdaniellift
的位置。 - Benjamin Hodgsontransform
只在 transformers-0.5 中不可能出现的上下文中使用,那么为什么它会对所有代码都产生影响呢?抱歉我很蠢。 - jakubdaniel