Search code examples
haskellfunctional-programmingconsolemonadsghci

Calling a custom monad in haskell using the bind


I am currently 'getting my feet wet with monads' (http://learnyouahaskell.com/a-fistful-of-monads#getting-our-feet-wet-with-maybe) and still struggling with part of this concept. I understand the maybe monad mentioned there and can see how to call it, as mentioned here:

ghci> return "WHAT" :: Maybe String  
Just "WHAT"  
ghci> Just 9 >>= \x -> return (x*10)  
Just 90  
ghci> Nothing >>= \x -> return (x*10)  
Nothing  

How do I however call my own monad instance rather than the maybe one if I declare my own instance with its own type, like so:

newtype CustomM a = CustomM {runCustomM:: a -> String}


instance Monad CustomM where
  return a = CustomM (\a -> mempty)
  m >>= f = CustomM (\a -> mempty)


instance Functor CustomM where 
  fmap = liftM 
instance Applicative CustomM where 
  pure = return; (<*>) = ap

using the return will just call the Maybe Monad I suspect. And what about the >>= it would require me to give it a certain type.

NB. I have only made the bind the same way as the return, because I still struggle with understanding what it is supposed to return, and how I can give it a monad m and call the function f on it's value a, when I don't specify the packed type more thoroughly in the left side. But I shall make another post about that.


Solution

  • You can create a value of your CustomM type just like you did with Maybe, using return:

    cm = return "WHAT" :: CustomM String
    

    You can also run it, after a fashion:

    Prelude Control.Monad> runCustomM cm "foo"
    ""
    

    Clearly, though, since you've hard-coded it to return mempty, it returns the mempty value for String, which is "".

    All that said, though, a -> String is contravariant in a, so it can't be a useful Functor instance. And since it can't be a useful Functor instance, it also can't be a useful Monad instance.

    While you can define a degenerate implementation as in the OP, you're not going to have much success making CustomM do anything for real.

    Try, instead, swapping the types like e.g. String -> a.