Scala 存在类型与重复参数
在Scala中,存在类型作用域是否可能覆盖重复参数的类型 动机 在本例中,我使用以下case类:Scala 存在类型与重复参数,scala,types,Scala,Types,在Scala中,存在类型作用域是否可能覆盖重复参数的类型 动机 在本例中,我使用以下case类: case class Rect2D[A, N <: Nat](rows: Sized[Seq[A], N]*) 存在式在*下,因此我不能保证所有行都具有相同的第二个类型参数,例如,以下编译,但不应该: Rect2D(Sized(1, 2, 3), Sized(1, 2)) 以下版本具有我想要的语义: case class Rect2D[A](rows: Seq[Sized[Seq[A],
case class Rect2D[A, N <: Nat](rows: Sized[Seq[A], N]*)
存在式在*
下,因此我不能保证所有行都具有相同的第二个类型参数,例如,以下编译,但不应该:
Rect2D(Sized(1, 2, 3), Sized(1, 2))
以下版本具有我想要的语义:
case class Rect2D[A](rows: Seq[Sized[Seq[A], N]] forSome { type N <: Nat })
以及:
我不想编译Y(X(1),X(“1”)
。是的。我知道我可以写:
case class Y(xs: Seq[X[B]] forSome { type B })
或:
但是我想使用重复的参数,不想在
B
上参数化Y
,举个简单的例子:
您可以在Y上声明其他类型参数:
案例类别Y[V](xs:X[V]*)
此类型参数应该是可推断的,因此从用户角度不需要额外编写。如果这不违反您的约定,因为您不关心N,您可以利用协方差丢弃存在类型,如下所示:
case class X[A](a: A)
case class Y(xs: X[_]*)
trait Nat
trait Sized[A,+B<:Nat]
object Sized {
def apply[A,B<:Nat](natSomething:B,items: A *) = new Sized[Seq[A],B] {}
}
class NatImpl extends Nat
case class Rect2D[A](rows:Sized[Seq[A],Nat] * )
val sizedExample = Sized(new NatImpl,1,2,3)
Rect2D(Sized(new NatImpl,1,2,3),Sized(new NatImpl,1,2,3),Sized(new NatImpl,1,2,3))
trait-Nat
特征大小[A,+B注:我以前在这里有一个不同的、不起作用的解决方案,但我把它删掉了
编辑:现在是第4版
sealed trait Rect2D[A] extends Product with Serializable { this: Inner[A] =>
val rows: Seq[Sized[Seq[A], N]] forSome { type N <: Nat }
def copy(rows: Seq[Sized[Seq[A], N]] forSome { type N <: Nat } = this.rows): Rect2D[A]
}
object Rect2D {
private[Rect2D] case class Inner[A](rows: Seq[Sized[Seq[A], N]] forSome { type N <: Nat }) extends Rect2D[A]
def apply[A, N <: Nat](rows: Sized[Seq[A], N]*): Rect2D[A] = Inner[A](rows)
def unapply[A](r2d: Rect2D[A]): Option[Seq[Sized[Seq[A], N]] forSome { type N <: Nat }] = Inner.unapply(r2d.asInstanceOf[Inner[A]])
}
Rect2D[A]使用可序列化{this:internal[A]=>
val rows:Seq[Sized[Seq[A],N]]对于某些{type N,用于简化示例的答案
(以下第一个例子的答案)
看起来您并不关心案例类Y(xs:X[\u]*)
中X[\u]
的精确类型参数,只要它们都是相同的。您只想阻止用户创建不尊重这一点的Y
实现这一点的一种方法是将默认的Y
构造函数设置为私有:
case class Y private (xs: Seq[X[_]])
// ^^^^^^^ makes the default constructor private to Y, xs is still public
// Note also that xs is now a Seq, we will recover the repeated arg list below.
并以这种方式定义自己的构造函数:
object Y {
def apply[B](): Y = Y(Nil)
def apply[B](x0: X[B], xs: X[B]*): Y = Y(x0 +: xs)
// Note that this is equivalent to
// def apply[B](xs: X[B]*): Y = Y(xs)
// but the latter conflicts with the default (now private) constructor
}
object Rect2D {
def apply[A,N <: Nat](r0: Sized[Seq[A], N], rs: Sized[Seq[A], N]*): Rect2D[A] = Rect2D[A](r0 +: rs) // Same as above
case class Rect2DBuilder[A]() {
def apply(): Rect2D[A] = Rect2D[A](Nil)
def apply[N <: Nat](r0: Sized[Seq[A], N], rs: Sized[Seq[A], N]*): Rect2D[A] = Rect2D[A](r0 +: rs)
}
def apply[A] = new Rect2DBuilder[A]
}
现在人们可以写作了
Y()
Y(X("a"))
Y(X(1), X(1), X(5), X(6))
Y[Int](X(1), X(1), X(5), X(6))
以下内容无法编译:
Y(X(1), X("1"))
第一个例子的答案
我们将构造函数设为私有,并将重复参数列表更改为Seq,如上所述:
case class Rect2D[A] private (rows: Seq[Sized[Seq[A], _]])
// ^^^^^^^ ^^^^ ^
让我们定义自己的构造函数:
但以下情况并不适用:
val r5 = Rect2D(Sized[Seq](1, 2), Sized[Seq](1, 2, 3))
一个缺点是你不能写这样的东西
val r2 = Rect2D[Int](Sized[Seq](1, 2), Sized[Seq](2, 3))
// ^^^^^
你必须写下这个
val r2 = Rect2D[Int, Nat._2](Sized[Seq](1, 2), Sized[Seq](2, 3))
// ^^^^^^^^
让我们来解决这个问题
第一个示例的增强解决方案
一个更干净的解决方案是通过以下方式定义构造函数:
object Y {
def apply[B](): Y = Y(Nil)
def apply[B](x0: X[B], xs: X[B]*): Y = Y(x0 +: xs)
// Note that this is equivalent to
// def apply[B](xs: X[B]*): Y = Y(xs)
// but the latter conflicts with the default (now private) constructor
}
object Rect2D {
def apply[A,N <: Nat](r0: Sized[Seq[A], N], rs: Sized[Seq[A], N]*): Rect2D[A] = Rect2D[A](r0 +: rs) // Same as above
case class Rect2DBuilder[A]() {
def apply(): Rect2D[A] = Rect2D[A](Nil)
def apply[N <: Nat](r0: Sized[Seq[A], N], rs: Sized[Seq[A], N]*): Rect2D[A] = Rect2D[A](r0 +: rs)
}
def apply[A] = new Rect2DBuilder[A]
}
下面的代码将不会编译
val r4 = Rect2D[Int](Sized[Seq](1, 2), Sized[Seq]("a", "b"), Sized[Seq](2, 3), Sized[Seq](2, 3))
// ^^^^^ ^^^^^^^^
在您的简化示例中,case class Y[B](xs:X[B]*)
不是一个有效的解决方案吗?@Nicolas:对不起,这个问题没有明确表明我试图避免那个解决方案(这正是我在链接答案中使用的方法)。我已经编辑了以使其更清晰。谢谢,但我确实关心参数,因为我需要它对所有项都相同。编译器可以在案例类Y(对于某些{type B},xs:Seq[X[B]]中验证这一点)
case,所以我不明白为什么重复参数是不可能的。为了响应您的更新:我可以使用forSome
将存在的范围提升到外部Seq
。我想对重复参数版本做同样的操作。case类Y(xs:X[B]*forSome{type B})
只是没有编译。scala>类X[A]定义类X scala>案例类Y(对于某些{type B}*)定义类Y,xs:X[B]与
版本相同,很不幸。谢谢-我没有想到尝试这个,但遗憾的是,存在主义仍然在*
:Rect2D(大小(1,2),大小(3))
编译,但不应该编译。您的第二个版本有几个问题:第一行中的括号需要移动,并在N
之前添加type
,以便语法正常工作。然后我仍然会得到一个“擦除后的相同类型”apply
错误。但是如果我删除案例
并使构造函数仅为私有
,它会提供我想要的用法。因此,到目前为止,这比任何其他方法都更接近,但由于它不适用于案例类,我将在接受之前再坚持一段时间。非常感谢-
val r5 = Rect2D(Sized[Seq](1, 2), Sized[Seq](1, 2, 3))
val r2 = Rect2D[Int](Sized[Seq](1, 2), Sized[Seq](2, 3))
// ^^^^^
val r2 = Rect2D[Int, Nat._2](Sized[Seq](1, 2), Sized[Seq](2, 3))
// ^^^^^^^^
object Rect2D {
def apply[A,N <: Nat](r0: Sized[Seq[A], N], rs: Sized[Seq[A], N]*): Rect2D[A] = Rect2D[A](r0 +: rs) // Same as above
case class Rect2DBuilder[A]() {
def apply(): Rect2D[A] = Rect2D[A](Nil)
def apply[N <: Nat](r0: Sized[Seq[A], N], rs: Sized[Seq[A], N]*): Rect2D[A] = Rect2D[A](r0 +: rs)
}
def apply[A] = new Rect2DBuilder[A]
}
val r2 = Rect2D[Int](Sized[Seq](1, 2), Sized[Seq](2, 3))
val r4 = Rect2D[Int](Sized[Seq](1, 2), Sized[Seq]("a", "b"), Sized[Seq](2, 3), Sized[Seq](2, 3))
// ^^^^^ ^^^^^^^^