0

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.
asked Oct 3, 2017 at 18:01
8
  • You should write instance Monad EmptyMonad where (without a). Commented Oct 3, 2017 at 18:02
  • Furthermore it should be (EmptyMonad x y) >>= f = EmptyMonad (f x) (y + 1). (with f), otherwise the types do not match. Commented Oct 3, 2017 at 18:02
  • 1
    I would advise you to read Kinds and some type-foo and Making monads Commented Oct 3, 2017 at 18:43
  • 5
    As a complete aside to your problems understanding and using Haskell syntax, you are also going to have a semantic problem. Counting binds is not okay in monads; it violates the "return is an identity" law saying that return x >>= f = f x, since there are fewer binds on the right-hand side of the equation. (It seems to be everybody's first idea for a new monad, though, including mine!) Commented Oct 3, 2017 at 19:01
  • 1
    See this question which asks about a "counter monad" also. Commented Oct 3, 2017 at 20:25

1 Answer 1

1

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 f x 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.

user1
6111 gold badge7 silver badges12 bronze badges
answered Oct 3, 2017 at 18:11
Sign up to request clarification or add additional context in comments.

2 Comments

Why can't I use EmptyMonad fx (y+1) instead of fx {myState = y+1}?
@user1 Because fx is an EmptyMonad b, not a b. So EmptyMonad fx (y+1) would be an EmptyMonad (EmptyMonad b) -- a nested monadic value!

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.