A box for typeclasses

I think I may have a found an encoding that works with context functions.

trait Box[Typeclass[_]]:
  type Self
  protected def self: Self
  protected def inst: Typeclass[Self]
  inline def apply[U](f: Typeclass[Self] ?=> Self => U): U = f(using inst)(self)


class BoxImpl[Self0, Typeclass[_]](val self: Self0)(using val inst: Typeclass[Self0]) extends Box[Typeclass]:
  type Self = Self0


object Box:
  def apply[Self, Typeclass[_]](self: Self)(using Typeclass[Self]): Box[Typeclass] = BoxImpl(self)
  def unapply[Typeclass[_]](box: Box[Typeclass]): Some[Any] = Some(box.self)

And then:

trait Foo[A]:
  extension (a: A) def foo(i: Int): Int

given Foo[Int] with
  extension (a: Int) def foo(i: Int): Int = a * i

given Foo[String] with
  extension (a: String) def foo(i: Int): Int = a.length * i

def branch(switch: Boolean): Box[Foo] =
  if switch then Box(4) else Box("foo")

val box: Box[Foo] = branch(true)

box(_.foo(5)) // 20
2 Likes