1

I have defined in Haskell a custom monad combining state and error processing like this:

import Control.Applicative
import Control.Monad

data Result a e = Ok a | Error e

newtype StateError s e a = StateError { runStateError :: s -> (Result a e, s) }

instance Functor (StateError s e) where
  fmap f m = StateError $
    \s -> case runStateError m s of
            (Ok x, s1) -> (Ok (f x), s1)
            (Error e, s1) -> (Error e, s1)

instance Applicative (StateError s e) where
  pure x = StateError $ \s -> (Ok x, s)
  a <*> b = ap a b

instance Monad (StateError s e) where
  return = pure

  m >>= f = StateError $
    \s -> case runStateError m s of
            (Ok x, s1) -> runStateError (f x) s1
            (Error e, s1) -> (Error e, s1)

get = StateError $ \s -> ((Ok s), s)

put s = StateError $ \_ -> ((Ok ()), s)

main = return ()

The code compiles fine, but it seems there is some redundancy here between the definitions of fmap and the >>= bind operator in the monad.

How can I redefine the bind operator to leverage the functor definition?

If this is not possible, why am I forced to define a functor for my custom monad?
It seems useless if I am not going to use fmap anywhere.

Thanks

NOTE: I know monad transformers exist, and perhaps they are the right way to combine the existing state and error monads into one, but I preferred this route for learning reasons (I have little experience with monads).

NOTE: This question is a follow-up of my other question How to create a monad that combines state and error in Haskell.

mljrg
  • 3,545
  • 1
  • 27
  • 42
  • 1
    This question is no longer necessary, because it was responded in the link provided by in the answer to the question [How to create a monad that combines state and error in Haskell](https://stackoverflow.com/questions/52513998/how-to-create-a-monad-that-combines-state-and-error-in-haskell/52514310?noredirect=1#52513998). – mljrg Sep 26 '18 at 10:34
  • `fmap = liftM` can be used if you want to reuse the Monad instance. – 4castle Sep 26 '18 at 10:44
  • @4castle How does it differ from `fmap f x = x >>= (pure . f)` in the "adding" link on the other question, copied [here](https://ideone.com/a2NTSt) ? – mljrg Sep 26 '18 at 10:50
  • 1
    @4castle Got it after looking in [Hoogle](https://www.haskell.org/hoogle/?hoogle=liftM) for [`liftM`](http://hackage.haskell.org/package/base-4.12.0.0/docs/src/GHC.Base.html#liftM): they are equivalent definitions. – mljrg Sep 26 '18 at 11:11
  • It's OK to post an answer yourself and accept it, to signal that the question is resolved. :) – Will Ness Sep 26 '18 at 14:25

0 Answers0