Scala 基于原点的约束函数(路径相关类型?类型生成?)
对不起,这个标题太糟糕了,我不知道有没有更好的。下面是我的问题的一个粗略简化(如果它看起来很琐碎,很抱歉,这是毫无意义的):Scala 基于原点的约束函数(路径相关类型?类型生成?),scala,path-dependent-type,Scala,Path Dependent Type,对不起,这个标题太糟糕了,我不知道有没有更好的。下面是我的问题的一个粗略简化(如果它看起来很琐碎,很抱歉,这是毫无意义的): RList(受限列表)的思想是您不能调整其大小,也不能更改其中元素的顺序。但是,您可以使用一些函数,这些函数为您提供一个新的RList,其中包含更改的数据 现在需要一个函数来创建RLists。它可能有如下签名: 到目前为止,一切顺利。但现在是棘手的部分。我需要一个这样工作的函数: trait RList[T] { outer => type S protec
RList
(受限列表)的思想是您不能调整其大小,也不能更改其中元素的顺序。但是,您可以使用一些函数,这些函数为您提供一个新的RList,其中包含更改的数据
现在需要一个函数来创建RLists。它可能有如下签名:
到目前为止,一切顺利。但现在是棘手的部分。我需要一个这样工作的函数:
trait RList[T] { outer =>
type S
protected val wrapped: List[T]
def map[V](f: T => V) = new RList[V] {
type S = outer.S
protected val wrapped = outer.wrapped.map(f)
}
def zip[V](r: RList[V] { type S = outer.S }) = new RList[(T, V)] {
type S = outer.S
protected val wrapped = outer.wrapped.zip(r.wrapped)
}
}
object RList {
def toRList[T](ts: List[T]) = new RList[T] {
type S = this.type
protected val wrapped = ts
}
}
但是有一个额外的限制,即左
和右
具有相同的原点。因此,它们保证大小相同
e、 g.应编译的代码:
val x = toRList(List(1, 2, 3))
val y = x.map(_ * 2)
val z = y.map(_.toString)
zip(y,z)
e、 g.无法编译的代码
*注意:在我最初的问题中,对zip的约束需要是它们来自同一个“源”。仅仅保证它们的长度相同是不够的(更不用说,列表的大小在编译时是未知的)*
我还需要能够多次使用zip
,所以应该编译类似的东西
zip(a,zip(b,c))
(假设a
,b
和c
来自同一来源)
谢谢 这对你有用吗
object PathDependentTypes {
trait RListProducer {
trait RList[T] {
def map[V](f: T => V): RList[V]
def zip[V](r: RList[V]) : RList[(T, V)]
}
def getList[T]: RList[T] = ???
}
class A extends RListProducer
def main(args: Array[String]) {
val aSource = new A
val a = aSource.getList[Int]
val anotherSource = new A
val b = anotherSource.getList[String]
val m1 = a.map( _ * 2)
val m2 = a.map( _.toString)
val z1 = m1.zip(m2)
//val z2 = a.zip(b) //doesn't compile because A and B aren't the same.
val z3 : A#RList[(Int, (Int, String))] = a zip (m1 zip m2)
}
}
使
RList
成为生产者的一个内在特征的缺点是,在生产者之外编写带有RList
参数的方法或函数会变得不那么愉快,最终您会遇到很多这样的问题:
def foo[P <: RListProducer, T](rl: P#RList[T]) = ???
现在假设我们有以下内容:
val a = RList.toRList(1 :: 2 :: 3 :: Nil)
val b = a.map(_.toString)
val c = RList.toRList("1" :: "2" :: "3" :: Nil)
现在a zip b
(或a zip b zip a zip a
等)将编译,但如果您输入c
,您将得到一个编译器错误
注意:我最初写的
zip
如下:
def zip[V](r: RList[V])(implicit ev: r.S =:= S) = new RList[(T, V)] { ... }
这给出了一个稍微好一点的编译器错误消息,但如果您使用的是2.10之前的版本,则需要使用
-Ydependent方法类型打开依赖方法类型
埃里克:谢谢,真不敢相信我错过了!我不确定是否可以保证依赖的方法类型不会在scala的未来版本中消失,但如果您愿意理解这一点,这确实是更好的方法。@AlecZorab:请参阅我的编辑,您在这里并不真正需要依赖的方法类型。在任何情况下,它们在2.10中默认启用,所以我认为它们不会去任何地方。是的,我只是在尝试时发现了这一点。比我的解决方案好得多。@AlecZorab:谢谢——我认为你的方法在很多情况下都是有意义的,但它可能对这里的用户造成太大的负担。我完全同意你的意图。如果Matlab总是这样做,我会有更少的一个错误。
def foo[P <: RListProducer, T](rl: P#RList[T]) = ???
trait RList[T] { outer =>
type S
protected val wrapped: List[T]
def map[V](f: T => V) = new RList[V] {
type S = outer.S
protected val wrapped = outer.wrapped.map(f)
}
def zip[V](r: RList[V] { type S = outer.S }) = new RList[(T, V)] {
type S = outer.S
protected val wrapped = outer.wrapped.zip(r.wrapped)
}
}
object RList {
def toRList[T](ts: List[T]) = new RList[T] {
type S = this.type
protected val wrapped = ts
}
}
val a = RList.toRList(1 :: 2 :: 3 :: Nil)
val b = a.map(_.toString)
val c = RList.toRList("1" :: "2" :: "3" :: Nil)
def zip[V](r: RList[V])(implicit ev: r.S =:= S) = new RList[(T, V)] { ... }