4

私は次の考えを持っています:

trait Generator[A] {
  def generate: Stream[A]

  // (1) If A <: Int
  def +(other: Generator[Int]): Generator[Int] = (
   CustomGeneratorInt(
     (this.asInstanceOf[Generator[Int]].generate, other.generate)
     .zipped
     .map(_ + _))
  )

  // (2) If A <: Boolean
  def &&(other: Generator[Boolean]): Generator[Boolean] = ...
}

case class CustomGeneratorInt(val generate: Stream[Int]) extends Generator[Int]
case class ConstantInt(i: Int) extends Generator[Int] { def generate = Stream(i) }
case class ConstantBool(i: Boolean) extends Generator[Boolean] { def generate = Stream(i) }
case class GeneratorRandomInt(i: Int) extends Generator[Int] { def generate = ... }

ConstantInt(1) + ConstantInt(2) // (3) ok
ConstantBool(true) && ConstantBool(false) // (4) ok

ConstantInt(1) + ConstantBool(false) // (5)
ConstantBool(true) + ConstantInt(1) // (6) compiles but it's bad

ConstantBool(true) && ConstantInt(1) // (7)
ConstantInt(1) && ConstantBool(true) // (8) compiles but it's bad

(1) と (2) が適切なスキームで適用されていない場合、コンパイラ例外を発生させたいと思います。たとえば、(6) と (8) は現在コンパイルされていますが、コンパイルされるべきではありません。(5) と (7) はすでにコンパイルされていません。これらのメソッドを適用するこの型条件を指定する方法は?

4

1 に答える 1

11

一般化された型制約(この回答を参照) を使用して、目的を達成できます。

trait Generator[A] {
  def generate: Stream[A]

  def +(other: Generator[A])(implicit evidence: A =:= Int): Generator[Int] = ???
  def &&(other: Generator[A])(implicit evidence: A =:= Boolean): Generator[Boolean] = ???
}

case class GeneratorInt(i: Int) extends Generator[Int] { def generate = Stream(i) }
case class GeneratorBool(i: Boolean) extends Generator[Boolean] { def generate = Stream(i) }

GeneratorInt(1) + GeneratorInt(2) // (3) ok
GeneratorBool(true) && GeneratorBool(false) // (4) ok

GeneratorInt(1) + GeneratorBool(false) // (5) type mismatch
GeneratorBool(true) + GeneratorInt(1) // (6) type mismatch

GeneratorBool(true) && GeneratorInt(1) // (7) type mismatch
GeneratorInt(1) && GeneratorBool(true) // (8) type mismatch
于 2013-05-27T08:39:01.753 に答える