How to implement `stateMonad` directly ?

#1

State[S, A] can not be used in Monad[State], because trait Monad[M[_]]

my attempt: https://github.com/xieyuheng/pracat/blob/0ea77f66ec901a2c35c62dc3bc4dcf7f27991c97/src/main/scala/xieyuheng/pracat/monad_and_all_that/Tree.scala#L91

#2

You can express this in Scala but it’s very unpleasant out of the box. I recommend you use this compiler plugin which will allow you to write State[S, *].

#3

Try adding scalacOptions += "-Ypartial-unification" to your build.sbt.

In Scala 2.13 it should work without it.

#4

As @DavidGregory084 said, the kind-projector compiler plugin is probably what you want. Functional libraries like cats also use it, so it is pretty common to include when you are doing stuff with type classes.

Your current implementation should compile with partial unification, but implicitly looking up the Monad for State won’t work. But you don’t have to change much when using kind-projector:

implicit def stateMonad[S]: Monad[State[S, ?]] = new Monad[State[S, ?]] {
  def pure[A](a: A): State[S,A] = State(s => (a,s))
  def flatMap[A, B]
    (state: State[S,A])
    (f: A => State[S, B]): State[S, B] = State(s => {
      val (a:A ,s2) = state.mutation(s)
      f(a).mutation(s2)
  })
}

FWIW, without the plugin, you’d have to change the first line of that to:

implicit def stateMonad[S] = new Monad[({type T[A] = State[S, A]})#T] {

, which most people don’t find easily readable (it creates an anonymous object with a type member, which fixes the first parameter of State. Kind-projector does the same with nicer syntax)