Search code examples
scalatypesscala-3

Scala 3. Context bound and type lambda


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))
    }
}

Solution

  • 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]].