2011-07-20 16 views
4

パス依存型を返すメソッドを設計するにはどうすればよいですか?パス依存型を返す

:構築することができない、次の今

trait Tree { 
    trait Vertex 
    def root: Vertex 
    def addChild(parent: Vertex): Vertex 
} 

trait TreeFactory { def make: Tree } 

次の例では、私は意図的Vertexは、木全体で頂点をミックスすることは禁止(これは単なる一例である)されていることをTreeなどに依存するパスになりたいです

def test(f: TreeFactory): (Tree, Map[Tree#Vertex, Tree#Vertex]) = { 
    val t = f.make 
    var sq = IndexedSeq(t.root) 
    var m = Map.empty[t.Vertex, t.Vertex] 
    for(i <- 1 to 100) { 
    val p = sq(util.Random.nextInt(sq.size)) 
    val c = t.addChild(p) 
    m += c -> p 
    sq :+= c 
    } 
    (t, m) 
} 

私は返す明らかにマップがタイプTree#Vertexのが、パス依存頂点のキーと値を持つべきではありませんので...

error: type mismatch; 
found : scala.collection.immutable.Map[t.Vertex,t.Vertex] 
required: Map[Tree#Vertex,Tree#Vertex] 
Note: t.Vertex <: Tree#Vertex, but trait Map is invariant in type A. 
You may wish to investigate a wildcard type such as `_ <: Tree#Vertex`. (SLS 3.2.10) 
      (t, m) 
      ^

私は、ツリーの作成と親子マップのビルドアップを分離しようとした場合:

def test(t: Tree): Map[t.Vertex, t.Vertex] = { 
    var sq = IndexedSeq(t.root) 
    var m = Map.empty[t.Vertex, t.Vertex] 
    for (i <- 1 to 100) { 
    val p = sq(util.Random.nextInt(sq.size)) 
    val c = t.addChild(p) 
    m += c -> p 
    sq :+= c 
    } 
    m 
} 

これは別の理由で失敗した:"error: illegal dependent method type"

答えて

3

私のねじれた心は、この1思い付きました。私は、よりエレガントな解決策があると思います。

trait Gagaism { 
    val tree: Tree 
    val map: Map[tree.Vertex, tree.Vertex] 
} 

def test(f: TreeFactory) = new Gagaism { 
    val tree = f.make 
    val map = { 
    var sq = IndexedSeq(tree.root) 
    var m = Map.empty[tree.Vertex, tree.Vertex] 
    for (i <- 1 to 100) { 
     val p = sq(util.Random.nextInt(sq.size)) 
     val c = tree.addChild(p) 
     m += c -> p 
     sq :+= c 
    } 
    m 
    } 
} 
+1

-Ydependent-method-typesを使用していない場合は、これ(従属型で依存する値をパッケージ化する)が推奨されます。 –

+0

ありがとうございます、それは動作します。私が思ったように、 '-Xexperimental'は必要ないので、なぜこれを明示的に有効にする必要があるのだろうか? –

0

私はあなたの最初の試みがうまくいかない理由を説明するのに十分な型システムを理解していないが、これは有界抽象型で、私は通常、続くパターン(ありますメンバー)がコンパイルします。より確信が持てるように、TreeTreeFactoryの実装を見てうれしいです。

package trees 

trait Tree { 
    trait Vertex 

    type V <: Vertex 
    def root: V 
    def addChild(parent: V): V 
} 

trait TreeFactory { def make : Tree } 

object Test { 
    def test(f: TreeFactory): (Tree, Map[Tree#Vertex, Tree#Vertex]) = { 
    val t = f.make 
    var sq = IndexedSeq(t.root) 
    var m = Map.empty[t.Vertex, t.Vertex] 
    for (i <- 1 to 100) { 
     val p = sq(util.Random.nextInt(sq.size)) 
     val c = t.addChild(p) 
     m += c -> p 
     sq :+= c 
    } 
    (t, m) 
    } 
} 
+1

私の具体的なケースでは、頂点は順序に関連付けられており、各順序付けを同じ順序付けで取得した要素に匹敵するものに限定したいと考えています。順序は 'Int'タグを維持するので、技術的に順序を混ぜることに何も問題はありません。パスに依存する型は、これが起こるのを防ぐ良い方法を提供します。順序(またはここではツリー)を比較することは、ほぼ確実にバグです。実際に、私のコードが動作した後(ガガイズムの方法)、コンパイラは確かに私がその正確な間違いを犯した少なくとも1つの場所を見つけました。このアプローチの素晴らしさを確認しました –

1

-Xexperimental -Ydependent-method-typesで従属メソッドのタイプを実験的にサポートすることができます。

+0

本当にありがとうございます( '-Ydependent-method-types'のみが必要です) –

+0

このフラグにはどのバージョンのScalaが必要ですか?私はScala 2.10.3で「悪いオプション:-Yependent-method-types」を取得します。 – rightfold

+0

依存型がデフォルトで有効になりました。 –