在 scala shapeless 中,是否可以将文字类型用作泛型类型参数? [英] In scala shapeless, is it possible to use literal type as a generic type parameter?

查看:44
本文介绍了在 scala shapeless 中,是否可以将文字类型用作泛型类型参数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我正在编写一个向量乘法程序.遵循本文中的要求:

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

只有当两个向量的维数相等时,乘法才能成功编译.为此,我定义了一个通用类型 Axis,它使用一个无形的文字类型(维数)作为类型参数:

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)
}

到目前为止一切顺利,但是当我尝试将其概括为所有 n 时出现了问题:

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

我的问题是:为什么 Spark 无法专注于更精细的类型 Witness.`1`.T,而是使用类型 Int?覆盖此行为需要什么才能成功定义案例类 KN?

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?

更新 1: 后续已移至新问题:

当利用Scalaless的单例类型特性,如何强制编译器使用窄/单例类型作为隐式参数?

推荐答案

Scala 无法推断 W 给定 W#T 这并不奇怪,因为通常也就是说,两个不同的 W 可能具有相同的 W#T.不适用于见证类型,但编译器不会对其进行特殊处理.

It isn't surprising that Scala can't infer W given W#T, because generally speaking it's possible for two different Ws to have the same W#T. Not for witness types, but they aren't treated specially by the compiler.

我期望的工作(但不确定为什么不这样做)是指定类型参数:

What I expected to work (and not sure why it doesn't) is to specify the type parameter:

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))

它似乎符合您问题中的要求,但我不知道它是否适用于您的其余代码.

It seems to suit the requirements in your question, but I don't know if it'll work with the rest of your code.

您可能还想考虑这种在 Scala 2.13 中不需要 Shapeless 的替代方案:

You may also want to consider this alternative which doesn't require Shapeless in Scala 2.13:

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)

这篇关于在 scala shapeless 中,是否可以将文字类型用作泛型类型参数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆