是否可以在monadic序列中更改monad类型?

Bru*_*rry 6 monads haskell either

我知道可以更改包装类型,以便您可以拥有

f :: (a -> m b)
g :: (b -> m c)
f >>= g :: (a -> m c)
Run Code Online (Sandbox Code Playgroud)

但是有可能改变m吗?如果mMonadError,由一个实现既Either ErrorAEither ErrorB,可不知何故,我把它们连?显然我不能直接链接它们,因为它的类型是Left什么?但是,我遇到的情况是我最后show都要打电话,但我找不到更好的解决方案

case mightFail1 of
  Left e -> show e
  Right v -> either show doStuff mightFail2
Run Code Online (Sandbox Code Playgroud)

在没有我必须明确检查的情况下,它无法正确使用在第一个错误处停止的monadic行为.

J. *_*son 11

"改变容器"的整个概念被称为"自然变换".具体来说,我们需要一个能够在不影响内部变形的情况下转换容器的功能.我们可以通过使用确保类型系统中的情况forall.

-- natural transformation
type (m :~> n) = forall a. m a -> n a
Run Code Online (Sandbox Code Playgroud)

然后这些可以随时应用.例如,如果您可以转换,那么您可以ErrorA -> ErrorB进行一般操作

mapE :: (e -> e') -> (Either e :~> Either e')
mapE f (Left e)  = Left (f e)
mapE _ (Right a) = a
Run Code Online (Sandbox Code Playgroud)

您甚至可以使用类型运算符和求和类型.

-- a generic sum type
infixr 9 :+:
newtype (a :+: b) = Inl a | Inr b

liftE :: (Either e :~> Either (e' :+: e))
liftE = mapE Inr
Run Code Online (Sandbox Code Playgroud)

Bifunctors实现了大致相同的效果,但它们是一种完全不同的方式来查看问题.它们不是通常更换容器,而是影响容器本身的另一个协变参数(或索引).因此,Bifunctor动作总是被视为自然变换,但NT更为通用.


lef*_*out 7

在monadic链中不可能这样做.

请注意,这根本不是真的关心Monad:你不会以任何方式绑定参数中的嵌套monadic动作Left或类似的东西,但你只是在改变参数本身.它基本上是仿函数操作fmap,但是在Left而不是Right部分:

fmap     :: (r->?) -> Either l r -> Either l ?
fmapLeft :: (l->?) -> Either l r -> Either ? r
Run Code Online (Sandbox Code Playgroud)

令人惊讶的是,具有该特定签名的功能似乎不存在.然而,这个带有两个协变参数的仿函数的想法显然比仅仅更普遍Either,而且确实有专门的类.它有(IMO相当不幸的命名,冲突Arrow)

Data.Bifunctor.first :: (a -> b) -> p a c -> p b c
Run Code Online (Sandbox Code Playgroud)

其中擅长于

first :: (a -> b) -> Either a c -> Either b c
Run Code Online (Sandbox Code Playgroud)

所以你可以使用

f :: (Show a) => (Either a b) -> (Either String b)
f = first show
Run Code Online (Sandbox Code Playgroud)