Сопоставление с образцом для абстрагированных классов - PullRequest
3 голосов
/ 21 ноября 2011

Я пытаюсь абстрагировать классы дел в модуле, используя зависимые типы методов и ночные сборки компилятора (2.10.0.r26005-b20111114020239).Я нашел вдохновение в примере Miles Sabin .

Я не совсем понимаю, что не так в (автономном) коде ниже.Вывод зависит от порядка шаблонов в foo.

// afaik, the compiler doesn't not expose the unapply method
// for a companion object
trait Isomorphic[A, B] {
  def apply(x: A): B
  def unapply(x: B): Option[A]
}

// abstract module
trait Module {
  // 3 types with some contraints
  type X
  type Y <: X
  type Z <: X
  // and their "companion" objects
  def X: Isomorphic[Int, X]
  def Y: Isomorphic[X, Y]
  def Z: Isomorphic[Y, Z]
}

// an implementation relying on case classes
object ConcreteModule extends Module {
  sealed trait X { val i: Int = 42 }
  object X extends Isomorphic[Int, X] {
    def apply(_s: Int): X = new X { }
    def unapply(x: X): Option[Int] = Some(x.i)
  }
  case class Y(x: X) extends X
  // I guess the compiler could do that for me
  object Y extends Isomorphic[X, Y]
  case class Z(y: Y) extends X
  object Z extends Isomorphic[Y, Z]
}

object Main {
  def foo(t: Module)(x: t.X): Unit = {
    import t._
    // the output depends on the order of the first 3 lines
    // I'm not sure what's happening here...
    x match {
      // unchecked since it is eliminated by erasure
      case Y(_y) => println("y "+_y)
      // unchecked since it is eliminated by erasure
      case Z(_z) => println("z "+_z)
      // this one is fine
      case X(_x) => println("x "+_x)
      case xyz => println("xyz "+xyz)
    }
  }
  def bar(t: Module): Unit = {
    import t._
    val x: X = X(42)
    val y: Y = Y(x)
    val z: Z = Z(y)
    foo(t)(x)
    foo(t)(y)
    foo(t)(z)
  }
  def main(args: Array[String]) = {
    // call bar with the concrete module
    bar(ConcreteModule)
  }
}

Есть идеи?

1 Ответ

1 голос
/ 22 ноября 2011

Предупреждения являются правильными и ожидаемыми, поскольку, если смотреть изнутри foo, Y и Z будут стерты до предела, т.е.X.

Что более удивительно, так это то, что наличие либо совпадения с Y, либо совпадения с Z нарушает совпадение с X, т.е.в этом случае

def foo(t: Module)(x: t.X): Unit = {
  import t._
  // the output depends on the order of the first 3 lines
  // I'm not sure what's happening here...
  x match {
    // unchecked since it is eliminated by erasure
    // case Y(_y) => println("y "+_y)
    // unchecked since it is eliminated by erasure
    // case Z(_z) => println("z "+_z)
    // this one is fine
    case X(_x) => println("x "+_x)
    case xyz => println("xyz "+xyz)
  }
}

результат равен

x 42
x 42
x 42

, что представляется разумным, тогда как при восстановлении одного из более ранних совпадений

def foo(t: Module)(x: t.X): Unit = {
  import t._
  // the output depends on the order of the first 3 lines
  // I'm not sure what's happening here...
  x match {
    // unchecked since it is eliminated by erasure
    case Y(_y) => println("y "+_y)
    // unchecked since it is eliminated by erasure
    // case Z(_z) => println("z "+_z)
    // this one is fine
    case X(_x) => println("x "+_x)
    case xyz => println("xyz "+xyz)
  }
}

результат

xyz AbstractMatch$ConcreteModule$X$$anon$1@3b58fa97
y AbstractMatch$ConcreteModule$X$$anon$1@3b58fa97
xyz Z(Y(AbstractMatch$ConcreteModule$X$$anon$1@3b58fa97))

, что не означает: я не вижу веских причин, по которым дополнительный случай может привести к выбору xyz вместо X, поэтому я думаю, что вы столкнулись сошибка в шаблоне соответствия.Я предлагаю вам поискать в Scala JIRA аналогичные проблемы, и если вы не можете их найти, откройте заявку с минимизированным примером воспроизведения, извлеченным из приведенного выше.

Если честно, во втором примере выше я хотел бымы ожидали, что регистр Y будет выбран во всех трех случаях благодаря стиранию Y в X и регистру Y, предшествующему регистру X в выражении соответствия.Но мы здесь на неконтролируемой территории, и я не на 100% уверен в своей интуиции.

...