scala - In scala shapeless, is it possible to use literal type as a generic type parameter?
问题描述
Assuming that I'm writing a program for vector multiplication. Following the requirement in this article:
https://etrain.github.io/2015/05/28/type-safe-linear-algebra-in-scala
The multiplication should only compile successfully if the dimension of both vectors are equal. For this I define a generic type Axis
that uses a shapeless literal type (the number of dimension) as the type parameter:
import shapeless.Witness
trait Axis extends Serializable
case object UnknownAxis extends Axis
trait KnownAxis[W <: Witness.Lt[Int]] extends Axis {
def n: Int
def ++(that: KnownAxis[W]): Unit = {}
}
object KnownAxis {
val w1 = Witness(1)
val w2 = Witness(2)
case class K1(n: Witness.`1`.T) extends KnownAxis[w1.type]
case class K2(n: Witness.`2`.T) extends KnownAxis[w2.type]
// K2(2) ++ K1(1) // doesn't compile
K2(2) ++ K2(2)
}
So far so good, the problem however appears when I try to generalise it for all n:
case class KN[W <: Witness.Lt[Int]](n: W#T) extends KnownAxis[W]
KN(1)
The above code triggers a compilation error:
Axis.scala:36: type mismatch;
found : Int(1)
required: this.T
[ERROR] KN(1)
[ERROR] ^
[ERROR] one error found
My question is: why Spark is incapable of focusing on the more refined type Witness.`1`.T
, instead it is using type Int
? What does it take to override this behaviour so case class KN
can be successfully defined?
UPDATE 1: The follow up has been moved to a new question:
解决方案
Scala 无法推断W
given并不奇怪W#T
,因为一般来说,两个不同W
的 s 可能具有相同的W#T
。不适用于见证类型,但编译器不会对它们进行特殊处理。
我期望工作(不知道为什么不工作)是指定类型参数:
KN[Witness.`1`](1)
// error: type arguments [scala.this.Any] do not conform to method apply's type parameter bounds [W <: shapeless.this.Witness.Lt[scala.this.Int]]
或更可能
KN[w1.type](1)
// error: type mismatch;
// found : scala.this.Int(1)
// required: .this.T
有什么作用:
case class KN[W <: Witness.Lt[Int]](w: W) extends KnownAxis[W] {
val n = w.value
}
KN(Witness(1))
它似乎符合您问题中的要求,但我不知道它是否适用于您的其余代码。
您可能还想考虑这种在 Scala 2.13 中不需要 Shapeless 的替代方案:
trait Axis extends Serializable
case object UnknownAxis extends Axis
trait KnownAxis[W <: Int with Singleton] extends Axis {
def n: W
def ++(that: KnownAxis[W]): Unit = {}
}
case class KN[W <: Int with Singleton](n: W) extends KnownAxis[W]
KN(1)
对于 2.12
import shapeless.syntax.singleton._
...
KN(1.narrow)
推荐阅读
- java - 一对多关系的问题
- python - 如何将 URL 拆分为三个不同的变量
- image - 将对抗样本保存到图像中并加载回来,但攻击失败
- gitlab - 单个项目或组的 Gitlab 访问令牌?
- ios - 由于 fetchedstatsarray 为空,我的 CSV 未完全生成,但为什么我的 fetchedstatsarray 为空?
- vue.js - 如何将 Vue.js 路由与数据道具一起使用?
- python - 为什么 PIL.ImageChops.difference 和 np.array 差异有不同的结果?
- android - 将 SDK 更改为 12 后 Android Studio 崩溃
- pyspark - 如何在没有模式的情况下查询数据框和 rdd
- javascript - 当其他 AJAX 函数已经执行时,第二个 AJAX 函数失败