Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to change the monad type in a monadic sequence?

I know it's possible to change the wrapped type, so that you can have

f :: (a -> m b)
g :: (b -> m c)
f >>= g :: (a -> m c)

but is it possible to change m? If m is a MonadError and is implemented both by an Either ErrorA and Either ErrorB, can i somehow chain them? Obviously I can't chain them directly, because what would be the type of Left? However, I'm in a situation where I end up calling show in either case, but I haven't found a better solution than

case mightFail1 of
  Left e -> show e
  Right v -> either show doStuff mightFail2

which fails to properly use the monadic behavior of stopping at the first error without me having to check explicitly.

like image 449
BruceBerry Avatar asked Aug 05 '13 19:08

BruceBerry


People also ask

Is monad a Typeclass?

The Monad class As of GHC 7.10, the Applicative typeclass is a superclass of Monad , and the Functor typeclass is a superclass of Applicative . This means that all monads are applicatives, all applicatives are functors, and therefore all monads are also functors.

How does a monad work?

A monad is an algebraic structure in category theory, and in Haskell it is used to describe computations as sequences of steps, and to handle side effects such as state and IO. Monads are abstract, and they have many useful concrete instances. Monads provide a way to structure a program.

What are the monad laws?

A proper monad must satisfy the three monad laws: left identity, right identity, and associativity. Together, left identity and right identity are know as simply identity.

Is maybe a monad?

The Maybe sum type is a useful data type that forms a functor. Like many other useful functors, it also forms a monad.


1 Answers

The entire notion of "changing the container" is called a "natural transformation". Specifically, we want a function which transforms containers without affecting what's inside. We can ensure this is the case in the type system by using forall.

-- natural transformation
type (m :~> n) = forall a. m a -> n a

Then these can be applied whenever we want. For instance, if you can transform ErrorA -> ErrorB then there's a general operation for you

mapE :: (e -> e') -> (Either e :~> Either e')
mapE f (Left e)  = Left (f e)
mapE _ (Right a) = a

You can even get really fancy with type operators and sum types.

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

liftE :: (Either e :~> Either (e' :+: e))
liftE = mapE Inr

Bifunctors achieve roughly the same effect but they are a totally different way of viewing the problem. Instead of generally changing out the container, they affect another covariant parameter (or index) in the container itself. So, Bifunctor actions can always be seen as natural transformations, but NTs are more general.

like image 152
J. Abrahamson Avatar answered Sep 28 '22 06:09

J. Abrahamson