Reputation: 1116
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
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