Подтвердить что ты не робот

Попытка моделировать F-ограниченный полиморфизм как член типа в Scala

Я хотел попробовать написать тип, методы которого могут быть однородными и возвращать значения одного и того же типа:

object SimpleTest {
  trait Foo extends Product with Serializable {
    type Self <: Foo
    def bar: Self
  }

  case class X() extends Foo {
    type Self = X
    def bar = this
  }

  case class Y() extends Foo {
    type Self = Y
    def bar = this
  }


  trait TC[A]

  implicit val tc: TC[Foo] = new TC[Foo] { }

  def tester[A: TC](x: Seq[A]) = "foo"

  // tester(Seq(X(), Y()))
}

К сожалению, пропущенная строка, вызывающая tester, терпит неудачу со следующей ошибкой (Scala 2.10):

Error: could not find implicit value for evidence parameter of type
SimpleTest.TC[SimpleTest.Foo{type Self >: SimpleTest.Y with SimpleTest.X <: SimpleTest.Foo}]
tester(Seq(X(), Y()))
      ^

В принципе, я в замешательстве, почему X и Y не объединяются в Foo, что кажется явным LUB для двух из них. Очевидно, член типа усложняет вопросы, но его границы, по-видимому, соблюдаются.

На более высоком уровне я ищу легкий способ получить эквивалент F-ограниченного полиморфизма без накладных расходов на всепроникающие параметры типа. В основном это работает, но мне нужно добавить аннотации, которые заставляют X и Y объединяться в Foo.

4b9b3361

Ответ 1

Я думаю, что это пример того, что вы ищете:

sealed trait Event { self =>
  type E >: self.type <: Event
  def instance: E = self
}

case class UserJoined() extends Event {
  type E = UserJoined
}

case class UserLeft() extends Event {
  type E = UserLeft
}

Если вы хотите прочитать больше, этот фрагмент из недавнего сообщения, который охватывает связанные понятия.

Изменить: для завершения ответа это будет:

scala> trait Foo extends Product with Serializable with Event{}
defined trait Foo

scala> case class X() extends Foo {
     |     type Self = X
     |     def bar = this
     |   }
defined class X

scala> case class Y() extends Foo {
     |     type Self = Y
     |     def bar = this
     |   }
defined class Y

scala> List(X(),Y())
res9: List[Foo] = List(X(), Y())

scala>   def tester[A: TC](x: Seq[A]) = "foo"
tester: [A](x: Seq[A])(implicit evidence$1: TC[A])String

scala>  tester(Seq(X(), Y()))
res10: String = foo