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