Learning Scala 3.
Notice type projection + context bound in monadWriter
trait Monoid[A] {
def zero: A
def append(a1: A, a2: A): A
}
trait Monad[F[_]] {
def unit[A](a: A): F[A]
def flatMap[A, B](fa: F[A])(f: A => F[B]): F[B]
def map[A, B](fa: F[A])(f: A => B): F[B] = {
flatMap(fa)(a => unit(f(a)))
}
}
given monadWriter[W: Monoid]: Monad[({type l[x] = Writer[x, W]})#l] = new Monad[({type l[x] = Writer[x, W]})#l] {
override def unit[A](a: A): Writer[A, W] =
Writer(a, implicitly[Monoid[W]].zero)
override def flatMap[A, B](fa: Writer[A, W])(f: A => Writer[B, W]): Writer[B, W] = {
val fa2 = f(fa.v)
Writer(fa2.v, implicitly[Monoid[W]].append(fa.w, fa2.w))
}
}
that code works ok.
Question: how can i refactor above code to Scala 3 type lambda syntax? How can I properly specify context bound to Monoid?
Below code fails to compile (unhappy about types in overrides):
given monadWriter[A, W: Monoid]: Monad[[W]=>>Writer[A,W]] = new Monad[[W]=>>Writer[A,W]] {
override def unit[A](a: A): Writer[A, W] =
Writer(a, implicitly[Monoid[W]].zero)
override def flatMap[A, B](fa: Writer[A, W])(f: A => Writer[B, W]): Writer[B, W] = {
val fa2 = f(fa.v)
Writer(fa2.v, implicitly[Monoid[W]].append(fa.w, fa2.w))
}
}
It should be
given monadWriter[W: Monoid]: Monad[[x] =>> Writer[x, W]] = new Monad[[x] =>> Writer[x, W]]:
override def unit[A](a: A): Writer[A, W] = ???
override def flatMap[A, B](fa: Writer[A, W])(f: A => Writer[B, W]): Writer[B, W] = ???
or better
given [W: Monoid]: Monad[[x] =>> Writer[x, W]] with
override def unit[A](a: A): Writer[A, W] = ???
override def flatMap[A, B](fa: Writer[A, W])(f: A => Writer[B, W]): Writer[B, W] = ???
summon[Monoid[W]]
should be instead of implicitly[Monoid[W]]
.