Home > database >  Scala context bounds in generalized algebraic datatype
Scala context bounds in generalized algebraic datatype

Time:06-07

Consider the following Scala 3 code, where Obj[_] refers to a type class and Context is a generalized algebraic datatype.

enum Context[T: Obj]:
  case Empty[U <: Unit: Obj]() extends Context[U]
  case Variable[A: Obj](x: A) extends Context[A]
  case Product[A: Obj, B: Obj](ctx1: Context[A], ctx2: Context[B])(using Obj[(A,B)]) extends Context[(A,B)]
  
def lookup[A: Obj, B: Obj](ctx: Context[A], x: B) =
  ctx match
    case Product(ctx1, ctx2): Context[(a1,b1)] =>
       // No implicit argument of type Obj[a1] was found for an implicit parameter of method lookup.
      lookup[a1,B](ctx1, x)
    ...

The Scala compiler is not able to infer that type a1 has the context bound Obj, even though the bound is declared in the Product case. Is there a way to solve this problem without passing the implicits explicitly everywhere?

CodePudding user response:

Apparently, Scala doesn't extract the implicits of constructors. The solution is to extract them explicitly:

enum Context[T: Obj]:
  case Product[A, B](ctx1: Context[A], ctx2: Context[B])
                    (using val aObj: Obj[A], val bObj: Obj[B], val pObj: Obj[(A,B)])
                    extends Context[(A,B)]
  ...
import Context.*
  
def lookup[A: Obj, B: Obj](ctx: Context[A], x: B): Unit =
  ctx match
    case p @ Product(ctx1, ctx2): Context[(a1,b1)] =>
      given Obj[(a1, b1)] = p.pObj
      given Obj[a1] = p.aObj
      given Obj[b1] = p.bObj
      lookup[a1,B](ctx1, x)
    ...
  • Related