Yogesh Sajanikar
Yogesh Sajanikar

Reputation: 1116

Defining Monad of nested monads

I am trying to define an instance of a monad for a type, which is defined as follows:

type Error a = Either String a
data Outer a = Outer { fromOuter :: Error (Maybe a) } 

Functors and Applicative instances for the Outer type can be defined as:

instance Functor Outer where
    f `fmap` (Outer fa) = Outer $ fmap (fmap f) $ fa 


instance Applicative Outer where
     pure = Outer . pure . pure
     (Outer l) <*> (Outer r) = Outer $ do
                             el <- l
                             er <- r
                             return $ el <*> er

However, I am struggling to define bind for defining Monad instance for this type:

instance Monad Outer where
    return = pure
    (Outer l) >>= f = ??????

Further question is:

How the above can be generalised to, say,

data Outer m n a = Outer { fromOuter :: m (n a) }

This problem is an abstraction of a issue in hedis-simple where I am trying to define Monad instance for RedisTx

Upvotes: 2

Views: 113

Answers (1)

Lee
Lee

Reputation: 144206

The type of your >>= function should be

Outer a -> (a -> Outer b) -> Outer b

Since you only have an a in the case where the Outer value is (Right (Just x)) for some x you can do:

instance Monad Outer where
  return = pure
  (Outer l) >>= f = case l of
    Left e -> Outer (Left e)
    Right Nothing -> Outer (Right Nothing)
    Right (Just x) -> f x

As for your second question, you can't. Given two monads M and N their composition M N cannot be automatically be made into a monad. See this question for more details.

Upvotes: 4

Related Questions