例如, Context 'State Progress returns 0' {
mock Get-Status {return $true} -Verifiable
$State = [PSCustomObject]@{Progress = 0}
$result = Confirm-Session
it 'should be' {
$result | should be "Session for $Name not initiated. Retrying."
}
}
定义为:
MaybeT
但不是:
newtype MaybeT m a =
MaybeT { runMaybeT :: m (Maybe a)}
为什么会这样?
答案 0 :(得分:6)
扩展新类型后,我们在第一种情况下为join :: Monad m => m (Maybe (m (Maybe a))) -> m (Maybe a)
,在第二种情况下为join :: Monad m => Maybe (m (Maybe (m a))) -> Maybe (m a)
。
要实施第一个join
,您需要一种方法将Maybe
分发到m
:dist1 :: Monad m => Maybe (m a) -> m (Maybe a)
:
join1 :: m (Maybe (m (Maybe a))) -> m (Maybe a)
join1 = fmap join . join . fmap dist1
要实施第二个join
,您需要相反的分配法dist2 :: Monad m => m (Maybe a) -> Maybe (m a)
join2 :: Maybe (m (Maybe (m a))) -> Maybe (m a)
join2 = fmap join . join . fmap dist2
dist1
很容易实现(我将向您证明monad变压器法律):
dist1 :: Monad m => Maybe (m a) -> m (Maybe a)
dist1 = sequenceA
dist2
并不那么容易。对于任意Monad
,无法做到这一点。作为一个反例,让我们选择m
成为“读者”monad (->) r
:
dist2 :: (r -> Maybe a) -> Maybe (r -> a)
由于您无法访问r
,因此dist2
的唯一实施方案是const Nothing
,这显然不符合monad法律。
答案 1 :(得分:2)
查看StateT
可能很有启发性:
newtype StateT s m a = StateT { runStateT :: s -> m (a,s) }
这里的状态既不是"内部"也"外部",但它的类型与它正在转换的monad交错,一些位在内部,一些在外部。确实
newtype ReaderT r m a = ReaderT { runReaderT :: r -> m a }
全部"外部"。所以它取决于它是什么变压器。可能有一些类别理论至少部分地解释了这种交错,我很想知道它(知识分子?)。
与适用的仿函数形成对比
newtype Compose f g a = Compose { getCompose :: f (g a) }
也是一个应用,因此总有一个明确的内部/外部"关系。您可以制作仅适用于StateT
的{{1}},并按Compose (State s)
找到其结构:
ApplicativeStateT s f a = s -> (s, f a)
事实上,如果你在右边作曲,还有另外一个:
ApplicativeStateT' s f a = f (s -> (s,a))
但是monad没有这样的规律性。