8

Given a typeclass Printer with a dependent type Show[A]:

trait Printer {
  type Show[A]
  def show[A](x: A)(implicit z: Show[A]): String
}

object Printer {
  // the intent here is this is the dumb fallback
  // and a user can have a better alternative in scope
  implicit val dumbPrinter: Printer = new Printer {
    type Show[A] = DummyImplicit
    def show[A](x: A)(implicit z: DummyImplicit): String = x.toString
  }
}

How do I encode this method:

def r[A](x: A)(implicit printer: Printer, show: printer.Show[A]): String =
  printer.show(x)(show)

I've been trying to adapt the working code in @MilesSabin's gist https://gist.github.com/milessabin/cadd73b7756fe4097ca0 and @TravisBrown's blog post https://meta.plasm.us/posts/2015/07/11/roll-your-own-scala/, but I can't find an encoding that works.

Dale Wijnand
  • 5,854
  • 4
  • 25
  • 53
  • Isn't it a problem of the lack of multiple implicit parameters sections in Scala? I think Miles Sabin made a SI with this recently, but I can't find it. (edit: I see this is already mentioned in the gist you refer to) – Haspemulator May 27 '16 at 09:32
  • @Haspemulator Correct. – Dale Wijnand May 27 '16 at 10:00
  • I didn't look at the examples. But how about making a new type that tuples a `Printer` and `Show[A]`: `case class Printable[A](printer: Printer)(implicit show: printer.Show[A])`. Then make `r` require a `Printable[A]`. – ziggystar May 27 '16 at 11:08

1 Answers1

0

You can force type inference one step at a time by introducing intermediate contexts:

object example {

  trait AnyPrinter {
    type Show <: AnyShow
  }

  trait AnyShow {
    type X
    def apply(x: X): String
  }

  def print[P <: AnyPrinter](implicit p: P): print[P] = new print[P]

  class print[P <: AnyPrinter] {
    def it[E](e: E)(implicit s: P#Show { type X = E }): String = s(e)
  }

  // the intent here is this is the dumb fallback
  // and a user can have a better alternative in scope
  implicit object DumbPrinter extends AnyPrinter {
    type Show = AnyDumbShow
  }
  trait AnyDumbShow extends AnyShow {
    def apply(x: X): String = x.toString
  }
  case class DumbShow[Z]() extends AnyDumbShow { type X = Z }
  implicit def dumbShow[Z]:DumbShow[Z] = DumbShow()

  val buh: String = print.it(2)
}
Eduardo Pareja Tobes
  • 2,850
  • 1
  • 16
  • 18