Search code examples
scalafunctional-programmingmonadsscala-cats

How to stack the State and IO monads


In a game of Connect4:

  • we start with an empty grid
  • two players place pieces x and o on the grid
  • the first player to achieve 4 pieces in a line wins!
  • this is a text based console game

My thinking is that:

  • at each step of the game the Grid is transitioning from one state to another
  • hence i need to use the State monad
  • and because this is a console based app that involves io
  • in this case I also need to use the IO monad

Is this thinking correct?

Assuming the above is correct, which one of these is correct?

  • type StateInIO[S,A] = IO[State[S,A]]
  • type IOInState[S,A] = State[S,IO[A]]

I favour the second option, makes more sense to me.

Can I stack these monads (State, IO) in this way?


Solution

  • I think you should just write a working program and generalize/refactor it afterwards instead of overingeneering upfront. You need State[S, A] for business logic and IO[A] for interacting with the console. But you don't have to mix it.

    Then in the main class where you write a user-interaction loop you could leverage StateT which unifies both of your types.

    By the way IO[State[S,A]] doesn't look like a very useful type. It says that you can read State[S, A] from the real world. State is a function. There are no sensible ways to read a function from the real world. So most probably you need something less powerful. Of course this type makes sense in the context of monad transformers.