Scala преобразовать кортеж типов в кортеж родовых c типов - PullRequest
0 голосов
/ 20 февраля 2020

Скажем, у меня есть тип a, определенный как кортеж типов

type a = (Int, String, Int)

, и я определяю generi c class Foo как

class Foo[A]{}

есть ли какой-либо метод Scala (предпочтительно собственный Scala), который может преобразовать a в b, кортеж обобщенных c типов?

type b = (Foo[Int], Foo[String], Foo[Int])

Ответы [ 2 ]

5 голосов
/ 20 февраля 2020

Хотя на самом деле это невозможно с собственным scala без shapeless или макросом на уровне типа в scala 2. *, возможно создать функцию, которая отображает значение типа a на значение типа b. Одна вещь, которую вы должны сделать, это определить класс типов trait LiftFoo[T], который имеет единственный метод def lift[T](t: T)(implicit instance: LiftFoo[T]): Foo[T], и создать реализации для всех типов, которые вы когда-либо захотите.

Затем вы можете отобразить свой кортеж с помощью полифункции:

object Bla{
  import shapeless.syntax.std.tuple._
  import shapeless.syntax._
  import shapeless.poly._
  case class Foo[T](t: T)
  trait LiftFoo[T] {
    def liftImpl(t: T): Foo[T]
  }
  object LiftFoo {
    def lift[T](t: T)(implicit instance: LiftFoo[T]): Foo[T] = instance.liftImpl(t)
  }
  implicit val liftInt: LiftFoo[Int] = {Foo(_)}
  implicit val liftString: LiftFoo[String] = {Foo(_)}
  implicit val liftDouble: LiftFoo[Double] = {Foo(_)}

  val a: (Int, Int, String, Double) = ???
  object LiftFooPoly extends Poly1 {
    implicit def onLiftable[T: LiftFoo] = at[T](LiftFoo.lift[T])
  }
  val b = a.map{LiftFooPoly}
}

Однако, scala 3 (т.е. Dotty) позволит сделать это на уровне типа с лямбдами типа и типами соответствия . Typelambda позволяет использовать типы форм type LiftFoo[T] = [T] =>> Foo[T] и сопоставлять типы и кортежи в scala 3, теперь повторно составляя HList, и вы можете рекурсивно перемещаться по его элементам с помощью типов совпадений :

  type TupleLiftFoo[Xs <: Tuple] <: Tuple = Xs match
    case Unit => Unit
    case x *: xs => LiftFoo[x] *: TupleLiftFoo[xs]

0 голосов
/ 20 февраля 2020

Как упоминалось ранее, невозможно сделать это с Scala 2.x без использования некоторых сложных магов уровня типа c (в данном случае Shapeless). Моя реализация использует обобщенное представление c и содержит некоторые комментарии для обозначения некоторых вспомогательных вещей.

Чтобы полностью понять, как работают обобщенные представления c, вы должны прочитать хотя бы первую пару главы Бесформенное руководство .

object Demo extends App {

  import shapeless._
  import syntax.std.tuple._
  import poly._

  // Generic representation of the input type
  val tupleGen = Generic[(Int, String, Int)]

  // Generic representation of the output type
  val tupleFooGen = Generic[(Foo[Int], Foo[String], Foo[Int])]

  // The type we want to lift all tuple members into
  class Foo[A] {}

  // The instance of the input type
  val input = (42, "four two", 43)

  // The "natural transformation" thing
  object liftFoo extends (Id ~> Foo) {
    def apply[T](t: T): Foo[T] = new Foo[T] {}
  }

  // Having done all the prep work, the conversion is really easy
  val result: (Foo[Int], Foo[String], Foo[Int]) =
    tupleFooGen.from(tupleGen.to(input).map(liftFoo))

  println(result)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...