Получить последовательность типов из HList в макросе - PullRequest
0 голосов
/ 11 января 2020

Контекст : я пытаюсь написать макрос, который статически осведомлен о нефиксированном количестве типов. Я пытаюсь передать эти типы в качестве параметра одного типа, используя HList. Это будет называться m[ConcreteType1 :: ConcreteType2 :: ... :: HNil](). Затем макрос создает оператор соответствия, который требует, чтобы некоторые комплименты были найдены во время компиляции, немного похоже на то, как json serialiser может требовать неявных кодировщиков. У меня есть рабочая реализация макроса при использовании фиксированного числа параметров типа, как показано ниже:

def m[T1, T2](): Int = macro mImpl[T1, T2]

def mImpl[T1: c.WeakTypeTag, T2: c.WeakTypeTag](c: Context)(): c.Expr[Int] = {
  import c.universe._
  val t = Seq(
    weakTypeOf[T1],
    weakTypeOf[T2]
  ).map(c => cq"a: $c => externalGenericCallRequiringImplicitsAndReturningInt(a)")
  val cases = q"input match { case ..$t }"
  c.Expr[Int](cases)
}

Вопрос : Если у меня есть WeakTypeTag[T] для некоторых T <: HList, есть ли способ превратить это в Seq[Type]?

def hlistToSeq[T <: HList](hlistType: WeakTypeTag[T]): Seq[Type] = ???

Мой инстинкт - написать рекурсивное совпадение, которое превращает каждый T <: HList в H :: T или HNil, но Я не думаю, что такой тип соответствия существует в scala.

. Я хотел бы услышать о любом другом способе получения списка типов произвольного размера в макрос, учитывая, что нужен Seq[Type], а не Expr[Seq[Type]], так как мне нужно отобразить их в макросе.

Способ написания подобного «макроса» в Dotty тоже был бы интересен - я надеюсь, что это » там будет проще, но еще не до конца изучено.

Редактировать (уточнение) : причина, по которой я использую макрос, в том, что я хочу пользователя библиотеки, которую я запись для предоставления коллекции типов (возможно, в форме HList), которые библиотека может перебирать и ожидать это относится к. Я говорю библиотека, но она будет скомпилирована вместе с использованием, чтобы макросы работали; в любом случае его следует использовать с разными коллекциями типов. Это немного сбивает с толку, но я думаю, что я решил это немного - мне просто нужно иметь возможность создавать макросы, которые могут работать со списками типов.

1 Ответ

1 голос
/ 11 января 2020

В настоящее время вам не нужны макросы. Кажется, классов типов или shapeless.Poly может быть достаточно.

def externalGenericCallRequiringImplicitsAndReturningInt[C](a: C)(implicit 
  mtc: MyTypeclass[C]): Int = mtc.anInt

trait MyTypeclass[C] {
  def anInt: Int
}
object MyTypeclass {
  implicit val mtc1: MyTypeclass[ConcreteType1] = new MyTypeclass[ConcreteType1] {
    override val anInt: Int = 1
  }

  implicit val mtc2: MyTypeclass[ConcreteType2] = new MyTypeclass[ConcreteType2] {
    override val anInt: Int = 2
  }

  //...
}

val a1: ConcreteType1 = null
val a2: ConcreteType2 = null
externalGenericCallRequiringImplicitsAndReturningInt(a1) //1
externalGenericCallRequiringImplicitsAndReturningInt(a2) //2
...