Подтвердить что ты не робот

Использование "Prolog in Scala" для поиска доступных экземпляров класса типа

Учитывая https://speakerdeck.com/folone/theres-a-prolog-in-your-scala, я хотел бы "злоупотреблять" системой типов Scala, чтобы найти все экземпляры, например. CanBuildFrom, которые соответствуют заданным критериям. Пролог, я бы оценил что-то в строках следующего псевдокода:

can_build_from(Src, int, list[int])
Src = somecollectiontype1[int]
Src = somecollectiontype2[int]
... etc

то есть. runtime будет искать все значения для Src, которые удовлетворяют утверждению can_build_from(Src, int, list[int]).

Теперь я знаю, что примитивная среда ограничения/логического программирования, в которой неявная система поиска Scala, не предназначена для использования для таких трюков и не может "вернуть" более одного найденного значение для Src из коробки, поэтому мой вопрос: есть ли "волшебный трюк", чтобы заставить его работать так, чтобы каким-то образом я получил все возможные значения для X в CanBuildFrom[X, Int, List[Int]]?

Дополнительный пример:

trait CanFoo[T, U]

implicit val canFooIntString  = new CanFoo[Int,     String] {}
implicit val canFooDblString  = new CanFoo[Double,  String] {}
implicit val canFooBoolString = new CanFoo[Boolean, String] {}
implicit val canFooIntSym     = new CanFoo[Int,     Symbol] {}
implicit val canFooDblSym     = new CanFoo[Double,  Symbol] {}
implicit val canFooBoolSym    = new CanFoo[Boolean, Symbol] {}

теперь я хотел бы запросить CanFoo[X, String] и вернуться X ∈ [Int, Double, Boolean], или CanFoo[Int, X] и вернуться X ∈ [String, Symbol].

В качестве альтернативы CanFoo[X, String] возвращает List(canFooIntString, canFooDblString, canFooBoolString), то есть все экземпляры CanFoo, которые соответствуют.

4b9b3361

Ответ 1

Это может быть сделано (по крайней мере, в некоторых случаях) с внутренними компонентами компилятора

import scala.language.experimental.macros
import scala.reflect.internal.util
import scala.reflect.macros.{blackbox, contexts}

object Macros {

  def allImplicits[A]: List[String] = macro impl[A]

  def impl[A: c.WeakTypeTag](c: blackbox.Context): c.Tree = {
    import c.universe._

    val context = c.asInstanceOf[contexts.Context]
    val global: context.universe.type = context.universe
    val analyzer: global.analyzer.type = global.analyzer
    val callsiteContext = context.callsiteTyper.context

    val tpA = weakTypeOf[A]

    val search = new analyzer.ImplicitSearch(
      tree = EmptyTree.asInstanceOf[global.Tree],
      pt = tpA.asInstanceOf[global.Type],
      isView = false,
      context0 = callsiteContext.makeImplicit(reportAmbiguousErrors = false),
      pos0 = c.enclosingPosition.asInstanceOf[util.Position]
    )

    q"${search.allImplicits.map(_.tree.symbol.toString).distinct}"
  }
}

allImplicits[CanFoo[_, String]]
// List(value canFooBoolString, value canFooDblString, value canFooIntString)

Проверено в 2.13.0.