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( 、、bおよびcが同じソースからのものであると想定)

ありがとう!

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

プロデューサーの内部特性を作成することの欠点の1つは、プロデューサーの外部で引数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

于 2012-08-19T13:01:09.913 に答える