用于转换任意大小的元组的多态函数

Polymorphic function to convert tuples of arbitrary size

我想创建一个多态函数,将各种大小的元组列表作为参数,return 一个相同类型的列表。因此,函数内的代码也应该进行调整。这里有一个例子来解释我的问题和我的目标:

val l2 = List( ("1","2"), ("3","4"))
val l3 = List( ("1","2","3"), ("4","5","6"))
val k2 = List( ("1","3"), ("5","7"))
val k3 = List( ("1","3","5"), ("7","9","11"))

def convertTuple2 ( l : List[(String,String)] ) : List[(Int,Int)] = {
    if (l.contains("1","2")) l.map{ case (a,b) => (a.toInt+10, b.toInt+10) }
    else l.map{ case (a,b) => (a.toInt, b.toInt) }
}

def convertTuple3 ( l : List[(String,String,String)] ) : List[(Int,Int,Int)] = {
    if (l.contains("1","2","3")) l.map{ case (a,b,c) => (a.toInt+10, b.toInt+10, c.toInt+10)}
    else l.map{ case (a,b,c) => (a.toInt, b.toInt, c.toInt) }
}

val l2converted = convertTuple2(l2)
val l3converted = convertTuple3(l3)
val k2converted = convertTuple2(k2)
val k3converted = convertTuple3(k3)

println(l2converted.mkString(",")) //printing (11,12),(13,14)
println(l3converted.mkString(",")) //printing (11,12,13),(14,15,16)
println(k2converted.mkString(",")) //printing (1,3),(5,7)
println(k3converted.mkString(",")) //printing (1,3,5),(7,9,11)

换句话说,如何创建一个既像 convertTuple2(...)convertTuple3(...) 又可能像 convertTupleN(...) 的独特函数?

这意味着 l.contains(...) 和模式匹配 { case ... => ... } 元素也必须根据输入列表中元组的大小进行调整。

什么是简单、优雅且高效的解决方案?

尝试

import shapeless.{HList, Nat, Poly1}
import shapeless.ops.hlist.Tupler
import shapeless.ops.tuple.{Length, Mapper}
import shapeless.ops.nat.ToInt
import shapeless.syntax.nat._
import shapeless.syntax.std.tuple._
import shapeless.poly.->
import shapeless.nat._

object toStringPoly extends Poly1 {
  implicit def `case`[N <: Nat](implicit 
    toInt: ToInt[N]
  ): Case.Aux[N, String] = at(_ => toInt().toString)
}

object toIntPoly extends (String -> Int)(_.toInt)
object toIntPoly1 extends (String -> Int)(s => s.toInt + 10)

def convertTuple[A <: Product, 
                 N <: Nat, 
                 L <: HList, 
                 B <: Product, 
                 C <: Product](l: List[A])(implicit
  length: Length.Aux[A, N],
  range: (_1 *--* N) { type Out = L },
  tupler: Tupler.Aux[L, B],
  toStringMapper: Mapper[B, toStringPoly.type],
  toIntMapper: Mapper.Aux[A, toIntPoly.type, C],
  toIntMapper1: Mapper.Aux[A, toIntPoly1.type, C],
) : List[C] =
  if (l.contains(range().tupled.map(toStringPoly))) 
    l.map(_.map(toIntPoly1))
  else l.map(_.map(toIntPoly))

import scala.collection.immutable.IndexedSeq
import shapeless.{HList, Nat, unexpected}
import shapeless.ops.hlist.Tupler
import shapeless.ops.tuple.{Length, Mapper}
import shapeless.ops.nat.ToInt
import shapeless.ops.traversable.ToSizedHList
import shapeless.syntax.std.tuple._
import shapeless.poly.->

object toIntPoly extends (String -> Int)(_.toInt)
object toIntPoly1 extends (String -> Int)(s => s.toInt + 10)

def convertTuple[A <: Product, N <: Nat, L <: HList, C <: Product](l: List[A])(implicit
  length: Length.Aux[A, N],
  toInt: ToInt[N],
  toSizedHList: ToSizedHList.Aux[IndexedSeq, String, N, Option[L]],
  tupler: Tupler[L],
  toIntMapper: Mapper.Aux[A, toIntPoly.type, C],
  toIntMapper1: Mapper.Aux[A, toIntPoly1.type, C],
) : List[C] =
  if (l.contains(toSizedHList((1 to toInt()).map(_.toString)).getOrElse(unexpected).tupled))
    l.map(_.map(toIntPoly1))
  else l.map(_.map(toIntPoly))