基于原点约束函数(路径依赖类型?类型生成?)

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)

但是有了额外的约束leftright具有相同的起源.因此,它们保证大小相同.

例如应编译的代码:

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是从相同的源)

谢谢!

Tra*_*own 4

创建生产者的内部特征的缺点之一是,在生产者 \xe2\x80\x94 之外RList编写带有参数的方法或函数变得不太令人愉快,最终会得到很多这样的结果:RList

\n\n
def foo[P <: RListProducer, T](rl: P#RList[T]) = ???\n
Run Code Online (Sandbox Code Playgroud)\n\n

另一种方法是为每个“源”提供RList一个唯一的类型成员RList,但每个源都会传递给其“子级”。像这样的东西:

\n\n
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}\n
Run Code Online (Sandbox Code Playgroud)\n\n

现在假设我们有以下内容:

\n\n
val a = RList.toRList(1 :: 2 :: 3 :: Nil)\nval b = a.map(_.toString)\nval c = RList.toRList("1" :: "2" :: "3" :: Nil)\n
Run Code Online (Sandbox Code Playgroud)\n\n

现在a zip b(或a zip b zip a zip a等)将编译,但如果你抛出一个,c你会得到一个编译器错误。

\n\n
\n\n

注意:我最初是zip这样写的:

\n\n
def zip[V](r: RList[V])(implicit ev: r.S =:= S) = new RList[(T, V)] { ... }\n
Run Code Online (Sandbox Code Playgroud)\n\n

这会提供稍微好一点的编译器错误消息,但如果您使用的是 2.10 之前的版本,则需要使用-Ydependent-method-types.

\n