【发布时间】:2021-01-31 05:30:08
【问题描述】:
我想创建一种可以用来验证元组是否同质的类型。我写了这个,应该保证T的所有元素都等于X(Scastie):
type Homogenous[X] = [T <: Tuple] =>> T match {
case EmptyTuple => DummyImplicit
case X *: t => Homogenous[X][t] //Doesn't work
case _ => Nothing
}
def f[T <: Tuple : Homogenous[String]](t: T) = ???
由于某种原因,第三行无法编译,出现以下错误:
Homogenous[X] 不带类型参数
但是,如果我让 Homogenous 接受 2 个参数,它会编译,但我不能再使用上下文绑定 (Scastie)。
type Homogenous[X, T <: Tuple] = T match {
case EmptyTuple => DummyImplicit
case X *: t => Homogenous[X, t]
case _ => Nothing
}
我不明白为什么会这样。并不是说 lambda [T] =>> 只是从匹配类型的特定情况下返回,所以编译器应该意识到 Homogenous[X] 总是带一个参数。这是一个错误还是我做错了什么,是否有修复/解决方法?
【问题讨论】:
-
这在某种程度上是意料之中的。当你有一个递归函数时,你总是必须先声明它,然后在定义中调用它,比如
val f = (a:Int) => (b:Int) => f(a)(b)将不起作用,因为它在编译时不知道 f 类型是什么,它不能进行类型推导和同时定义。所以你需要做val f: Int=>Int=>Int = a => b => f(a)(b)让它工作。但是对于类型定义,dotty 不允许在同一行声明(绑定)和定义,因此编译器不知道 Homogenous 是一个柯里化类型构造函数,因此您会看到错误。 -
@texasbruce 好点。但我想这还不是全部,因为
type U <: [T] =>> Any允许使用U[Int]类型,但如果我们在案例中添加上限type Homogenous[X] <: ([T <: Tuple] =>> Any) = [T <: Tuple] =>> T match { ...仍然无法编译。我怀疑这也可能是匹配类型如何转换为Matchdotty.epfl.ch/docs/reference/new-types/… -
@texasbruce “但对于类型定义,dotty 不允许声明(绑定)和定义在同一行” 对于匹配类型的上限和定义是允许的。见代码 sn-p
type Concat[Xs <: Tuple, +Ys <: Tuple] <: Tuple = Xs match {...dotty.epfl.ch/docs/reference/new-types/match-types.html -
@DmytroMitin 是的。看起来只有当 rhs 不是带有 match 子句的高阶类型时,才允许同时进行类型边界和定义。相当奇怪的要求。
-
@texasbruce 好吧,正如我在回答中提到的,多个类型参数列表未实现。也许
type Homogenous[X][T <: Tuple] = T match {...或type Homogenous = [X] =>> [T <: Tuple] =>> T match {...会编译。
标签: scala types scala-3 dotty match-types