2016-03-25 25 views
0

抽象型を使用しており、Scalaコンパイラが同じでなければならない2つの型を統一することに問題があります。これらは私の定義は以下のとおりです。抽象型との型の不一致

i1.chromosome(0) = 6 

と型エラーは次のとおりです:

trait Chromosome { 
    type Gene 

    val size : Int 

    def apply(idx : Int) : Gene 

    def update(idx : Int, g : Gene) 

    def indices = Range(0, size-1) 
} 


trait Individual { 
    type Fitness 
    implicit protected val ord: Ordered[Fitness] = implicitly[Ordered[Fitness]] 

    val chromosome : Chromosome 

    def size : Int = chromosome.size 

    def apply(idx : Int) : chromosome.Gene = chromosome.apply(idx) 
    def update(idx : Int, g : chromosome.Gene) = chromosome.update(idx, g) 

    protected var _fitness : Fitness = _ 
    def fitness : Fitness = _fitness 
    def fitness_=(f : Fitness):Unit = _fitness = f 
} 


case class ArrayChromosome(size : Int) extends Chromosome { 
    implicit protected val tag : ClassTag[Gene] = implicitly[ClassTag[Gene]] 

    protected val xs : Array[Gene] = new Array[Gene](size) 

    def apply(idx : Int) = xs(idx) 

    def update(idx : Int, g : Gene) = xs(idx) = g 
} 


abstract class ArrayIndividual(size : Int) extends Individual { 
    val chromosome = ArrayChromosome(size) 
} 


class MyIndividual(size : Int) extends ArrayIndividual(size) { 
    type Gene = Int 
    type Fitness = Double 
} 


object Test extends App { 
    val i1 = new MyIndividual(10) 

    i1.fitness = 10.5 
    i1.chromosome(0) = 6 
    print(i1) 
} 

はつまり、問題は、このラインである

Error:(75, 22) type mismatch; 
found : Int(6) 
required: abstractTypes.Test.i1.chromosome.Gene 
    i1.chromosome(0) = 6 

コンパイラが統一することができないようですi1.chromosome.GeneInt

私は2つの質問があります。

  1. は、それはコンパイラが両方のタイプを統一する手助けすることは可能ですか?
  2. 問題のある行を削除し、toStringIndividualに正しく設定したとします。 Testを実行すると、なぜjava.lang.NullPointerExceptionになるのですか?このエラーはGeneClassTagに関連しているようですが、わかりません。

@のSOM-snyttに対する応答のコード:Scalaで

abstract class ArrayIndividual(size : Int) extends Individual { 
    type Gene 
    implicit protected def tag2: ClassTag[Gene] 

    val chromosome = new ArrayChromosome(size) { 
    type Gene = ArrayIndividual#Gene 
    protected val tag : ClassTag[Gene] = tag2 
    } 
} 

class MyIndividual(size : Int) extends ArrayIndividual(size) { 
    type Fitness = Double 
    type Gene = Int 
    implicit protected val tag2 : ClassTag[Gene] = implicitly[ClassTag[Gene]] 

    override def toString = s"${super.toString} $chromosome" 
} 

答えて

1

は、タイプは、グローバルスコープされていません。 ChromosomeのメンバーとしてGeneと書いてありますが、Individualのサブクラス(「Chromosome」ではなく「Chromosome」)に定義しようとしています。

宣言と定義の場所を選択できますが、メソッドなどの用語メンバをオーバーライドする場合と同じように、同じ階層にする必要があります。

individual.Geneは、あなたの例ではchromosome.Geneとは関係ありません。

は、とにかくあなたがClassTagのためにそれを必要とするタイプの定義を移動し

case class ArrayChromosome(size : Int) extends Chromosome { 
    type Gene = Int 
    implicit protected val tag : ClassTag[Gene] = implicitly[ClassTag[Gene]] 

D'をああ、私はちょうどあなたが再帰的に自分の暗黙的に定義している気づきました。暗黙のうちにRHSに暗黙的に定義しているものを使用します。そうしないでください。コンパイラは暗黙的にそれ自身を呼び出します。

しかし、エイリアスタイプを修正しなかったスーパークラスに暗黙のタグを指定する必要がある場合、具象クラスに実装されるクラスタグを提供する抽象メソッドを持つことができます。あなたの答えのための

abstract class ArrayChromosome(val size : Int) extends Chromosome { 
    //type Gene = Int 
    //implicit protected val tag : ClassTag[Gene] = implicitly[ClassTag[Gene]] 
    implicit protected def tag: ClassTag[Gene] 

    protected lazy val xs : Array[Gene] = new Array[Gene](size) 

    def apply(idx : Int) = xs(idx) 

    def update(idx : Int, g : Gene) = xs(idx) = g 
} 


abstract class ArrayIndividual(size : Int) extends Individual { 
    //val chromosome = ArrayChromosome(size) 
    val chromosome = new ArrayChromosome(size) { 
    type Gene = Int 
    protected val tag = implicitly[ClassTag[Gene]] 
    } 
} 


class MyIndividual(size : Int) extends ArrayIndividual(size) { 
    type Fitness = Double 

    override def toString = s"${super.toString} $chromosome" 
} 
+0

おかげで、しかし、クラスArrayChromosomeで抽象的であるべきで、これだけを拡張するサブクラスで、後に定義され得る遺伝子を入力します。Individualサブクラスは、具体的なChromosomeを指定させる例えば

、。私は型パラメータを追加することができると思いますが、そのようなパラメータなしで統一問題を解決することは可能ですか? – pepeStck

+0

それは私がタグについてのコメントによって意味したものです。コード例を追加します。 –

+0

レイジーヴァルに注意してください。 –