我知道可以更改包装类型,以便您可以拥有
f :: (a -> m b)
g :: (b -> m c)
f >>= g :: (a -> m c)
但是可以更改
m
?如果 m
是 MonadError
并由 Either ErrorA
实现和 Either ErrorB
,我可以以某种方式链接它们吗?显然我不能直接链接它们,因为 Left
的类型是什么? ?但是,我遇到的情况是我最终调用了show
。在任何一种情况下,但我还没有找到比case mightFail1 of
Left e -> show e
Right v -> either show doStuff mightFail2
它无法正确使用在第一个错误处停止的单子(monad)行为,而无需我进行明确检查。
最佳答案
“改变容器”的整个概念被称为“自然转换”。具体来说,我们想要一个在不影响内部内容的情况下转换容器的函数。我们可以通过使用 forall
来确保类型系统中的情况。 .
-- natural transformation
type (m :~> n) = forall a. m a -> n a
然后可以随时应用这些。例如,如果您可以转换
ErrorA -> ErrorB
然后有一个通用的操作给你mapE :: (e -> e') -> (Either e :~> Either e')
mapE f (Left e) = Left (f e)
mapE _ (Right a) = a
您甚至可以对类型运算符和求和类型非常感兴趣。
-- a generic sum type
infixr 9 :+:
newtype (a :+: b) = Inl a | Inr b
liftE :: (Either e :~> Either (e' :+: e))
liftE = mapE Inr
双仿函数实现了大致相同的效果,但它们是看待问题的完全不同的方式。它们通常不会改变容器,而是影响容器本身的另一个协变参数(或索引)。因此,Bifunctor Action 总是可以看作是自然变换,但 NT 更一般。
关于haskell - 是否可以在单子(monad)序列中更改单子(monad)类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18066113/