Hep*_*tic 7 scala path-dependent-type
抱歉可怕的头衔,不确定更好的一个.这是我的问题的一个简单的简化(对不起,如果它看起来如此微不足道,这是毫无意义的):
class RList[T](data: List[T]) {
def map[V](f: T=>V): RList[V] = ...
}
Run Code Online (Sandbox Code Playgroud)
一个的想法RList(限制列表)是你不能调整其大小,或改变它的元素的顺序.但是您可以使用为您提供包含更改数据的新RList的函数.
现在需要有一个创建RList的函数.它可能有一个签名,如:
def toRList[T](values: List[T]): RList[T] = ...
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好.但现在是棘手的部分.我需要一个像这样工作的函数:
def zip[T, V](left: RList[T], right: RList[V]): RList[(T,V)]
Run Code Online (Sandbox Code Playgroud)
但是有了额外的约束left并right具有相同的起源.因此,它们保证大小相同.
例如应编译的代码:
val x = toRList(List(1, 2, 3))
val y = x.map(_ * 2)
val z = y.map(_.toString)
zip(y,z)
Run Code Online (Sandbox Code Playgroud)
例如,无法编译的代码
val y = toRList(List(2, 4, 6))
val z = toRList(List("one", "two"))
zip(y,z)
Run Code Online (Sandbox Code Playgroud)
*注意:在我原来的问题中,zip的约束必须是来自同一个"来源".仅仅保证它们的长度相同还不够(更不用说,在编译时不知道列表的大小)*
我还需要能够zip多次使用,所以这样的东西应该编译
zip(a,zip(b,c))
Run Code Online (Sandbox Code Playgroud)
(假设a,b并且c是从相同的源)
谢谢!
创建生产者的内部特征的缺点之一是,在生产者 \xe2\x80\x94 之外RList编写带有参数的方法或函数变得不太令人愉快,最终会得到很多这样的结果:RList
def foo[P <: RListProducer, T](rl: P#RList[T]) = ???\nRun Code Online (Sandbox Code Playgroud)\n\n另一种方法是为每个“源”提供RList一个唯一的类型成员RList,但每个源都会传递给其“子级”。像这样的东西:
trait RList[T] { outer =>\n type S\n protected val wrapped: List[T]\n\n def map[V](f: T => V) = new RList[V] {\n type S = outer.S\n protected val wrapped = outer.wrapped.map(f)\n }\n\n def zip[V](r: RList[V] { type S = outer.S }) = new RList[(T, V)] {\n type S = outer.S\n protected val wrapped = outer.wrapped.zip(r.wrapped)\n }\n}\n\nobject RList {\n def toRList[T](ts: List[T]) = new RList[T] {\n type S = this.type\n protected val wrapped = ts\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n\n现在假设我们有以下内容:
\n\nval a = RList.toRList(1 :: 2 :: 3 :: Nil)\nval b = a.map(_.toString)\nval c = RList.toRList("1" :: "2" :: "3" :: Nil)\nRun Code Online (Sandbox Code Playgroud)\n\n现在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)] { ... }\nRun Code Online (Sandbox Code Playgroud)\n\n这会提供稍微好一点的编译器错误消息,但如果您使用的是 2.10 之前的版本,则需要使用-Ydependent-method-types.