2

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

Yogesh Sajanikar
  • 1,086
  • 7
  • 19
  • 3
    Unfortunatley, monads don't compose. You've discovered a [Monad Transformer](https://hackage.haskell.org/package/transformers-0.4.3.0/docs/Control-Monad-Trans-Error.html) – AJF Dec 05 '15 at 10:33
  • It seems hedis-simple defines RedisTx in such a way that it is not possible to write monad instance for it. I wonder if simpler design decisions were possible to make. – Yogesh Sajanikar Dec 05 '15 at 18:17

1 Answers1

4

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.

Community
  • 1
  • 1
Lee
  • 142,018
  • 20
  • 234
  • 287