I'm learning category theory. I understand the concept of reader monad, it's even pretty easy to implement:
case class Reader[DEP, A](g: DEP => A) {
def apply(dep: DEP): A = g(dep)
def map[B](f: A => B): Reader[DEP, B] = Reader(dep => f(apply(dep)))
def flatMap[B](f: A => Reader[DEP, B]): Reader[DEP, B] = Reader(dep => f(apply(dep)) apply dep)
}
However, I have problems implementing it with constraint to some generic Monad interface, i.e
trait Monad[A] {
def pure(a: A): Monad[A]
def map[B](f: A => B): Monad[B]
def flatMap[B](f: A => Monad[B]): Monad[B]
}
let's forgot for a second that there's an applicative or functor and let's just put these 3 methods here.
Now, having this interface I have problems implementing ReaderMonad. map method is pretty straighforward, but what about pure and flatMap? What does it even mean to have pure on Reader? To implement flatMap, I need to have a function from A to Reader[DEP, B], but I have A => Monad[B], thus I'm not possible to access apply.
case class Reader[DEP, A](g: DEP => A) extends Monad[A] {
def apply(dep: DEP): A = g(dep)
override def pure(a: A): Reader[DEP, A] = Reader(_ => a) // what does it even mean in case of Reader
override def map[B](f: (A) => B): Reader[DEP, B] = Reader(dep => f(apply(dep)))
override def flatMap[B](f: (A) => Monad[B]): Reader[DEP, B] = ??? // to implement it, I need f to be (A) => Reader[DEP, B], not (A) => Monad[B]
}
Is it possible to implement it this way in scala? I tried to play around with self bound types, but it didn't work either. I know libraries like scalaz or cats uses typeclasses to implement these types, but this is just for educational purpose.
Monadtrait is wrong so you can't really implement this without casting as you've found. The usual implementation is to parameterise theMonadtrait with a type constructor and define it forReader[DEP, _]. - Lee