7

对不起,糟糕的标题,不确定更好的标题。这是对我的问题的粗略简化(对不起,如果它看起来如此微不足道,那毫无意义):

class RList[T](data: List[T]) {
   def map[V](f: T=>V): RList[V] = ...
}

(受限列表)的想法RList是您不能调整它的大小,或更改其中元素的顺序。但是您可以使用为您提供新 RList 的函数,其中包含已更改的数据。

现在需要一个创建 RList 的函数。它可能有一个类似的签名:

def toRList[T](values: List[T]): RList[T] = ...

到目前为止,一切都很好。但现在是棘手的部分。我需要一个这样工作的函数:

def zip[T, V](left: RList[T], right: RList[V]): RList[(T,V)]

left但是具有与right具有相同起源的附加约束。因此,它们保证大小相同。

例如应该编译的代码:

val x = toRList(List(1, 2, 3))
val y = x.map(_ * 2)
val z = y.map(_.toString)
zip(y,z)

例如应该无法编译的代码

val y = toRList(List(2, 4, 6))
val z = toRList(List("one", "two"))
zip(y,z)

*注意:在我原来的问题中,对 zip 的约束必须是它们来自同一个“来源”。仅仅保证它们的长度相同是不够的(更不用说,列表的大小在编译时是未知的)*

我还需要能够zip多次使用,所以应该编译这样的东西

zip(a,zip(b,c))

(假设a和来自同一来源)bc

谢谢!

4

2 回答 2

4

这对你有用吗?

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)
  }
}
于 2012-08-19T11:11:08.033 回答
4

制作生产者的内在特征的缺点之一RList是编写带有生产者之外的参数的方法或函数变得不那么愉快RList——你最终会得到很多这样的结果:

def foo[P <: RListProducer, T](rl: P#RList[T]) = ???

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

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)

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


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

def zip[V](r: RList[V])(implicit ev: r.S =:= S) = new RList[(T, V)] { ... }

这会给出一个更好的编译器错误消息,但如果您使用的是 2.10 之前的版本,则需要使用-Ydependent-method-types.

于 2012-08-19T13:01:09.913 回答