在 Scala 中处理高种类对象时类型信息丢失
Type information is lost when working with high-kinded objects in Scala
我正在尝试分解一些代码,但最终不得不使用更高级的类型。
以下最小示例工作正常:
trait Builder[M[_]] {
def build[A]: M[A]
def buildPair[A, B]: (M[A], M[B]) = (build[A], build[B])
}
class List[A]
class BuilderList extends Builder[List] {
def build[A] = new List[A]
}
val l: List[String] = (new BuilderList).build[String]
val ll: (List[String], List[Double]) = (new BuilderList).buildPair[String, Double]
defined trait Builder
defined class List
defined class BuilderList
l: List[String] = List@5c7754a7
ll: (List[String], List[Double]) = (List@62874648,List@7b0f6537)
如果我现在想将其应用于具有两个类型参数的类型,比如
class Map[K, V]
我希望能够写作
trait BuilderMap[K] extends Builder[Map[K, _]] {...}
但这当然行不通,因为 Scala 中的类型参数不是柯里化的。
我发现以下技巧让我通过了编译:
trait PartialApplier[F[_, _], K] {
type PartiallyApplied[_] = F[K, _]
}
class BuilderMap[K] extends Builder[PartialApplier[Map, K]#PartiallyApplied] {
def build[V] = new Map[K, V]
}
但是,一些奇怪的效果发生了,我无法弄清楚原因:
scala> val m: Map[Int, String] = (new BuilderMap[Int]).build[String]
m: Map[Int,String] = Map@71da0c64
scala> val mm: (Map[Int, String], Map[Int, Double]) = (new BuilderMap[Int]).buildPair[String, Double]
<console>:21: error: type mismatch;
found : (Map[Int, _], Map[Int, _])
required: (Map[Int,String], Map[Int,Double])
val mm: (Map[Int, String], Map[Int, Double]) = (new BuilderMap[Int]).buildPair[String, Double]
当我使用 PartialApplier
技巧时,higher-kinded trait Builder
中定义的函数似乎丢失了一些类型信息。
有没有办法让这一切顺利进行?也许 PartialApplier
技巧不是正确的方法!
在您 type PartiallyApplied[_] = F[K, _]
中的示例中,下划线未指定相同的类型。
如果您将 PartialApplier
定义为
,它会起作用
trait PartialApplier[F[_, _], K] {
type PartiallyApplied[V] = F[K, V]
}
此外,您可以完全避免使用 PartialApplier
,并像这样定义 Builder
类型参数:
class BuilderMap[K] extends Builder[({ type L[V] = Map[K, V] })#L] {
def build[V] = Map.empty[K, V]
}
我正在尝试分解一些代码,但最终不得不使用更高级的类型。 以下最小示例工作正常:
trait Builder[M[_]] {
def build[A]: M[A]
def buildPair[A, B]: (M[A], M[B]) = (build[A], build[B])
}
class List[A]
class BuilderList extends Builder[List] {
def build[A] = new List[A]
}
val l: List[String] = (new BuilderList).build[String]
val ll: (List[String], List[Double]) = (new BuilderList).buildPair[String, Double]
defined trait Builder
defined class List
defined class BuilderList
l: List[String] = List@5c7754a7
ll: (List[String], List[Double]) = (List@62874648,List@7b0f6537)
如果我现在想将其应用于具有两个类型参数的类型,比如
class Map[K, V]
我希望能够写作
trait BuilderMap[K] extends Builder[Map[K, _]] {...}
但这当然行不通,因为 Scala 中的类型参数不是柯里化的。
我发现以下技巧让我通过了编译:
trait PartialApplier[F[_, _], K] {
type PartiallyApplied[_] = F[K, _]
}
class BuilderMap[K] extends Builder[PartialApplier[Map, K]#PartiallyApplied] {
def build[V] = new Map[K, V]
}
但是,一些奇怪的效果发生了,我无法弄清楚原因:
scala> val m: Map[Int, String] = (new BuilderMap[Int]).build[String]
m: Map[Int,String] = Map@71da0c64
scala> val mm: (Map[Int, String], Map[Int, Double]) = (new BuilderMap[Int]).buildPair[String, Double]
<console>:21: error: type mismatch;
found : (Map[Int, _], Map[Int, _])
required: (Map[Int,String], Map[Int,Double])
val mm: (Map[Int, String], Map[Int, Double]) = (new BuilderMap[Int]).buildPair[String, Double]
当我使用 PartialApplier
技巧时,higher-kinded trait Builder
中定义的函数似乎丢失了一些类型信息。
有没有办法让这一切顺利进行?也许 PartialApplier
技巧不是正确的方法!
在您 type PartiallyApplied[_] = F[K, _]
中的示例中,下划线未指定相同的类型。
如果您将 PartialApplier
定义为
trait PartialApplier[F[_, _], K] {
type PartiallyApplied[V] = F[K, V]
}
此外,您可以完全避免使用 PartialApplier
,并像这样定义 Builder
类型参数:
class BuilderMap[K] extends Builder[({ type L[V] = Map[K, V] })#L] {
def build[V] = Map.empty[K, V]
}