Haskell 在单子转换器中,为什么已知的单子是内部的?
例如,Haskell 在单子转换器中,为什么已知的单子是内部的?,haskell,monads,monad-transformers,Haskell,Monads,Monad Transformers,例如,MaybeT被定义为: newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a)} 但不是: newtype MaybeT m a = MaybeT { runMaybeT :: Maybe (m a) } 这是为什么?在扩展新类型后,我们在第一种情况下有join::Monad m=>m(Maybe(Maybe(Maybe))->m(Maybe)(a),在第二种情况下有join::Monad m=>Maybe(Maybe(ma
MaybeT
被定义为:
newtype MaybeT m a =
MaybeT { runMaybeT :: m (Maybe a)}
但不是:
newtype MaybeT m a =
MaybeT { runMaybeT :: Maybe (m a) }
这是为什么?在扩展新类型后,我们在第一种情况下有
join::Monad m=>m(Maybe(Maybe(Maybe))->m(Maybe)(a)
,在第二种情况下有join::Monad m=>Maybe(Maybe(ma))->Maybe(ma)
要实现第一个join
您需要一种方法将Maybe
分发到m
:dist1::Monad m=>Maybe(ma)->m(Maybe a)
:
要实现第二个join
您需要相反的分布规律dist2::Monad m=>m(maybea)->maybea(ma)
dist1
易于实现(我将把monad transformer定律的证明留给您):
dist2
不是那么容易。不能对任意的单子执行此操作。作为反例,让我们选择m
作为“阅读器”monad(>)r
:
dist2 :: (r -> Maybe a) -> Maybe (r -> a)
由于您无法访问r
,因此将进行类型检查的dist2
的唯一实现是const Nothing
,这显然不符合monad定律。查看StateT
可能会有所启发:
newtype StateT s m a = StateT { runStateT :: s -> m (a,s) }
在这里,状态既不是“内部”也不是“外部”,但它的类型与它正在转换的单子交错,有些位在内部,有些位在外部。而且确实
newtype ReaderT r m a = ReaderT { runReaderT :: r -> m a }
都是“外部的”。所以这取决于它是什么变压器。可能有一些范畴理论至少部分解释了这种交错,我很想知道它(知识分子?)
与应用函子相比,应用函子
newtype Compose f g a = Compose { getCompose :: f (g a) }
也是一种应用程序,因此始终存在明确的“内部/外部”关系。您可以仅使应用程序成为StateT
,并通过Compose(states)
查找其结构:
事实上,如果你在右边作曲,还有一个:
ApplicativeStateT' s f a = f (s -> (s,a))
但是单子没有这样的规律性。因为我们变换的是可能单子,而不是可能包含的东西?我想这在以前的某个地方已经得到了回答,但我找不到它。我想直接关注join2
更容易发现问题,而不是试图对它必须如何分解进行太深入的推理。我们可以对参数进行模式匹配,然后我们需要m(Maybe(ma))->Maybe(ma)
。唯一不平凡的选择是只是
,这会导致m(可能是(ma))->ma
,闻起来有点麻烦。我怀疑我们给一些变压器起的名字可能暗示了一种错误的模式。我们在State
之后命名StateT
,在Reader
之后命名ReaderT
,等等,这似乎暗示了某种一对一的关系。但是单子和单子变形金刚确实有很大的不同,这可以从声称是“正确”单子变形金刚列表的各种事物中得到证明。“ListT
done right”、管道/管道/流媒体/机器/协同程序和LogicT
(以及LogicT
的无悔反射版本)似乎都对该标题有合法的要求。
newtype ReaderT r m a = ReaderT { runReaderT :: r -> m a }
newtype Compose f g a = Compose { getCompose :: f (g a) }
ApplicativeStateT s f a = s -> (s, f a)
ApplicativeStateT' s f a = f (s -> (s,a))