Search code examples
haskelltypesfunctional-programmingmonads

Using >> without explicitly declaring it in a monad


I am trying to get good at Monads and have written the following Monads and functions in which I use the >> (in the apply-function) although it is not declared in the Monad itself. How come this is possible to compile, as I understand http://learnyouahaskell.com/a-fistful-of-monads#walk-the-line it is required to declare it in the instantiation of the Monad as is the case with the Maybe Monad.

data Value =
    NoneVal
  | TrueVal | FalseVal
  | IntVal Int
  | StringVal String
  | ListVal [Value]
  deriving (Eq, Show, Read)

data RunErr = EBadV VName | EBadF FName | EBadA String
  deriving (Eq, Show)

newtype CMonad a = CMonad {runCMonad :: Env -> (Either RunErr a, [String]) }

instance Monad CMonad where
  return a = CMonad (\_ -> (Right a, []))
  m >>= f = CMonad (\env ->  case runCMonad m env of                   
          (Left a, strLst) -> (Left a, strLst)
          (Right a, strLst) -> let (a', strLst') = runCMonad (f a) env in (a', strLst ++ strLst')) 

output :: String -> CMonad ()
output s = CMonad(\env -> (Right (),  [] ++ [s]))

apply :: FName -> [Value] -> CMonad Value
apply "print" [] = output "" >> return NoneVal

Furthermore, how would I make it possible to show the output (print it) from the console when running apply. Currently I get the following error message, although my types have derive Show:

<interactive>:77:1: error:
* No instance for (Show (CMonad Value)) arising from a use of `print'
* In a stmt of an interactive GHCi command: print it

Solution

  • The >> operator is optional, not required. The documentation states that the minimal complete definition is >>=. While you can implement both >> and return, you don't have to. If you don't supply them, Haskell can use default implementations that are derived from either >> and/or Applicative's pure.

    The type class definition is (current GHC source code, reduced to essentials):

    class Applicative m => Monad m where
        (>>=)       :: forall a b. m a -> (a -> m b) -> m b
    
        (>>)        :: forall a b. m a -> m b -> m b
        m >> k = m >>= \_ -> k
      
        return      :: a -> m a
        return      = pure
    

    Notice that >>= lacks an implementation, which means that you must supply it. The two other functions have a default implementation, but you can 'override' them if you want to.

    If you want to see output from GHCi, the type must be a Show instance. If the type wraps a function, there's no clear way to do that.