Scala将类型元组转换为类型泛型元组

kri*_*ath 0 generics types scala

假设我将类型a定义为类型元组

type a = (Int, String, Int)
Run Code Online (Sandbox Code Playgroud)

我将泛型类定义Foo

class Foo[A]{}
Run Code Online (Sandbox Code Playgroud)

是否有任何方法是 Scala(最好是原生 Scala)可以转换ab泛型类型的元组?

type b = (Foo[Int], Foo[String], Foo[Int])
Run Code Online (Sandbox Code Playgroud)

Iva*_*Kam 5

尽管shapeless在 scala 2.* 中,对于没有typelevel 或宏的本机 scala来说这是不可能的,但可以创建一个函数,将类型 a 的值映射到类型 b 的值。您应该做的一件事是定义trait LiftFoo[T] 具有单一方法的typeclassdef lift[T](t: T)(implicit instance: LiftFoo[T]): Foo[T]并为您想要的所有类型实现。

然后你可以用 polyfunction 映射你的元组:

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}
}
Run Code Online (Sandbox Code Playgroud)

但是,scala 3(即 Dotty)将允许在类型级别使用lambdasmatch types执行此操作。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]

Run Code Online (Sandbox Code Playgroud)