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)] { ... }