Reputation: 10710
How to make this typecheck?
trait Test[A] {
type Output = A
def get: Iterable[A]
def check(a: A): Boolean
}
object A {
def fs: List[Test[_]] = ???
def test = for{f <- fs
a <- f.get
if f.check(a)} println(a)
}
It complains with
<console>:12: error: type mismatch;
found : a.type (with underlying type _$1)
required: _$1
if f.check(a)} println(a)
object A {
def fs: List[Test[_]] = ???
def test = for{f <- fs
a <- f.get
if f.check(a.asInstanceOf[f.Output])} println(a)
}
but then I have the same problem:
<console>:12: error: type mismatch;
found : f.Output
(which expands to) _$1
required: _$1
if f.check(a.asInstanceOf[f.Output])} println(a)
Having learned of some existential types, I am trying to replace the underscore -- at Test level, because not all A may be identical
object A {
def fs: List[Test[A] forSome { type A }] = ???
def test = for{f <- fs
a <- f.get
if f.check(a)} println(a)
}
It complains with:
<console>:12: error: type mismatch;
found : a.type (with underlying type A)
required: A
if f.check(a)} println(a)
How to get out of this type nightmare?
Upvotes: 1
Views: 1277
Reputation: 170909
The basic issue is that the Scala compiler doesn't notice that the types hidden by the existential must be the same.
There are two solutions:
Make a single method calling both get
and check
:
object A {
private def getChecked[A](f: Test[A]) = f.get.withFilter(f.check)
def fs: List[Test[_]] = ???
def test = for { f <- fs; a <- getChecked(f) } println(a)
Give name to the existential using a type variable pattern. Unfortunately, this doesn't seem to work inside a for
, so you'll need to desugar it first:
// equivalent to your initial code
def test = fs.flatMap { f => f.get.withFilter { a => f.check(a) } }.
foreach { a => println(a) }
// with a type variable
def test = fs.flatMap { case f: Test[x] => f.get.withFilter { a => f.check(a) } }.
foreach { a => println(a) }
Upvotes: 1
Reputation: 10710
The solution was to push the existential type inside.
object A {
def fs: List[Test[A forSome { type A }]] = ???
def test = for{f <- fs
a <- f.get
if f.check(a)} println(a)
}
And voilà it worked out.
Upvotes: 1