Consider the following code snippet:
case class Foo[A](a:A)
case class Bar[A](a:A)
def f[B](foo:Foo[Seq[B]], bar:Bar[Seq[B]]) = foo.a ++ bar.a
val s : Seq[T] forSome {type T} = Seq(1, 2, 3)
f(Foo(s), Bar(s))
The last line fails to type check, because Foo(s)
has type Foo[Seq[T]] forSome {type T}
and Bar(s)
has type Bar[Seq[T]] forSome {type T}
, i.e. each has its own existential quantifier.
Is there any way around this? In reality all I know about s
at compile time is that it has such an existential type. How can I force Foo(s)
and Bar(s)
to fall under the scope of a single existential quantifier?
Does this make sense? I'm pretty new to Scala and fancy types in general.
I realized it's possible to make this work with a little bit of refactoring:
case class Foo[A](a:A)
case class Bar[A](a:A)
def f[B](foo:Foo[Seq[B]], bar:Bar[Seq[B]]) = foo.a ++ bar.a
def g[B](s1:Seq[B], s2:Seq[B]) = f(Foo(s1), Bar(s2))
val s : Seq[T] forSome {type T} = Seq(1, 2, 3)
g(s)
Essentially I wrap the call to f
in another function g
that guarantees that the two sequences have the same type.