简体   繁体   中英

Making Haskell Monads

I'm trying to create a very simple monad in Haskell. The monad does nothing special but holding a counter as state.

module EmptyMonad
  ( EmptyMonad
  ) where

import Control.Monad

data EmptyMonad a = EmptyMonad
  { myValue :: a
  , myState :: Int
  } deriving (Show)

instance (Eq a) => Eq (EmptyMonad a) where
  EmptyMonad x1 y1 == EmptyMonad x2 y2 = x1 == x2 && y1 == y2


instance Monad (EmptyMonad a) where
  return x = EmptyMonad x 0
  (EmptyMonad x y) >>= f = EmptyMonad x (y + 1)

After spending few hours on Monads, I cannot get my head around the error from the compiler:

EmptyMonad.hs:16:10: error:
    • Expecting one fewer argument to ‘Monad EmptyMonad’
      Expected kind ‘k0 -> Constraint’,
        but ‘Monad EmptyMonad’ has kind ‘Constraint’
    • In the instance declaration for ‘Monad EmptyMonad a’
Failed, modules loaded: none.

There are two main problems here:

  • the instance declaration does expect a type of kind * -> * . So for instance [] , not [a] ; and
  • the bind operator >>= expect an EmptyMonad a , and a function a -> EmptyMonad b and returns an EmptyMonad b element.

So we can fix the problems with the following solution:

instance Monad EmptyMonad where  -- no a after EmptyMonad
  return x = EmptyMonad x 0
  (EmptyMonad x y) >>= f = fx {myState = y+1}
      where fx = f x

So here we specify instance Monad EmptyMonad since EmptyMonad has kind * -> * . Furthermore the bind operator will calculate fx and then alter the myState of that instance with y+1 .

That being said, nowadays you need to make EmptyMonad an instance of Applicative and Functor as well.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM