如何编写匹配具有不同签名的多个案例 类 的类型约束
How to write type constraints that match several case classes with different signatures
假设我有一些案例 class 有一个共同特征:
trait MyCaseClasses {
def generic: String
}
case class C1(l: List[Int], generic: String) extends MyCaseClasses
case class C2(s: String, generic: String) extends MyCaseClasses
case class C3(a: Int, b: Int, generic: String) extends MyCaseClasses
我想做的是创建一个函数,将这些情况 class 中的任何一个作为参数。类似于:
def caseClassCurry[T <: MyCaseClasses](generic: String, cc: T): (args) => T = {
(args) => cc(args, generic)
}
当然,这不会编译。这里有两个问题不知道怎么解决:
args
很难指定。它必须表示任何类型的可变数量的参数。你会怎么做?
当我写出这个版本时,我得到 cc.type does not take parameters
。我假设这是因为 cc
只继承了 MyCaseClasses
的特性,这是一个特征并且不接受参数 - 类型系统无法推断出 class 继承了特质可能有争论。我需要某种方式来表明 cc
实际上确实接受了参数(请参阅问题 1)。我将如何完成此操作?
最理想的是,我想更改特征 MyCaseClasses
以指示扩展它的 classes 将具有任意数量的 Any
类型的附加参数,但是那将如何是否大功告成也不清楚。
这个怎么样:
scala> trait F[T]{ def generic: String }
// defined trait F
scala> case class C1(l: List[Int], generic: String) extends F[List[Int]]
// defined case class C1
scala> case class C2(s: String, generic: String) extends F[String]
// defined case class C2
scala> def caseClassCurry[T](generic: String, cc: (T, String) => F[T]): T => F[T] = cc(_, generic)
def caseClassCurry[T](generic: String, cc: (T, String) => F[T]): T => F[T]
scala> caseClassCurry("c1", C1.apply)(List(1, 2, 3))
val res2: F[List[Int]] = C1(List(1, 2, 3),c1)
** 编辑 **
很抱歉在上述解决方案中遗漏了 C3
案例,我找到了另一个解决方案,但仅适用于 dotty
(即 scala3.0)。它可以通过在 scala2 中使用 shapeless
来工作:
scala> trait F { def generic: String }
// defined trait F
scala> case class C1(generic: String, list: List[Int]) extends F
// defined case class C1
scala> case class C2(generic: String, str: String) extends F
// defined case class C2
scala> case class C3(generic: String, a: Int, b: Long) extends F
// defined case class C3
scala> def curry[T <: Tuple, C <: F](generic: String, cc: String *: T => C): T => C = t => cc(generic *: t)
def curry[T <: Tuple, C <: F](generic: String, cc: String *: T => C): T => C
scala> curry("hello", C1.apply.tupled)(Tuple1(List()))
val res0: C1 = C1(hello,List())
scala> curry("hello", C2.apply.tupled)(Tuple1("world"))
val res1: C2 = C2(hello,world)
scala> curry("hello", C3.apply.tupled)((0, 1L))
val res2: C3 = C3(hello,0,1)
假设我有一些案例 class 有一个共同特征:
trait MyCaseClasses {
def generic: String
}
case class C1(l: List[Int], generic: String) extends MyCaseClasses
case class C2(s: String, generic: String) extends MyCaseClasses
case class C3(a: Int, b: Int, generic: String) extends MyCaseClasses
我想做的是创建一个函数,将这些情况 class 中的任何一个作为参数。类似于:
def caseClassCurry[T <: MyCaseClasses](generic: String, cc: T): (args) => T = {
(args) => cc(args, generic)
}
当然,这不会编译。这里有两个问题不知道怎么解决:
args
很难指定。它必须表示任何类型的可变数量的参数。你会怎么做?当我写出这个版本时,我得到
cc.type does not take parameters
。我假设这是因为cc
只继承了MyCaseClasses
的特性,这是一个特征并且不接受参数 - 类型系统无法推断出 class 继承了特质可能有争论。我需要某种方式来表明cc
实际上确实接受了参数(请参阅问题 1)。我将如何完成此操作?
最理想的是,我想更改特征 MyCaseClasses
以指示扩展它的 classes 将具有任意数量的 Any
类型的附加参数,但是那将如何是否大功告成也不清楚。
这个怎么样:
scala> trait F[T]{ def generic: String }
// defined trait F
scala> case class C1(l: List[Int], generic: String) extends F[List[Int]]
// defined case class C1
scala> case class C2(s: String, generic: String) extends F[String]
// defined case class C2
scala> def caseClassCurry[T](generic: String, cc: (T, String) => F[T]): T => F[T] = cc(_, generic)
def caseClassCurry[T](generic: String, cc: (T, String) => F[T]): T => F[T]
scala> caseClassCurry("c1", C1.apply)(List(1, 2, 3))
val res2: F[List[Int]] = C1(List(1, 2, 3),c1)
** 编辑 **
很抱歉在上述解决方案中遗漏了 C3
案例,我找到了另一个解决方案,但仅适用于 dotty
(即 scala3.0)。它可以通过在 scala2 中使用 shapeless
来工作:
scala> trait F { def generic: String }
// defined trait F
scala> case class C1(generic: String, list: List[Int]) extends F
// defined case class C1
scala> case class C2(generic: String, str: String) extends F
// defined case class C2
scala> case class C3(generic: String, a: Int, b: Long) extends F
// defined case class C3
scala> def curry[T <: Tuple, C <: F](generic: String, cc: String *: T => C): T => C = t => cc(generic *: t)
def curry[T <: Tuple, C <: F](generic: String, cc: String *: T => C): T => C
scala> curry("hello", C1.apply.tupled)(Tuple1(List()))
val res0: C1 = C1(hello,List())
scala> curry("hello", C2.apply.tupled)(Tuple1("world"))
val res1: C2 = C2(hello,world)
scala> curry("hello", C3.apply.tupled)((0, 1L))
val res2: C3 = C3(hello,0,1)