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

时间:2012-08-19 09:49:59

标签: scala path-dependent-type

对于可怕的头衔感到抱歉,不确定是否更好。这是我的问题的一个简单的简化(对不起,如果它似乎微不足道,这是毫无意义的):

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)]

但是leftright具有相同来源的附加约束。因此,它们保证大小相同。

e.g。应编译的代码:

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

e.g。应该编译

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

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

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

zip(a,zip(b,c))

(假设abc来自同一来源)

谢谢!

2 个答案:

答案 0 :(得分: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)
  }
}

答案 1 :(得分: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等)会编译,但如果你输入c,你将收到编译错误。


注意:我最初写的zip如下:

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

这会产生稍微好一点的编译器错误消息,但如果你在2.10之前工作,则需要使用-Ydependent-method-types启用依赖方法类型。