I have the following code which was supposed to take a function A => Boolean
(generic on the input type) and convert it to a generic trait Y[A]
through chained implicit conversions:
val f: Int => Boolean = ???
trait X[A] {
def m1: Unit
}
implicit def toX[A](f: A => Boolean): X[A] = ???
f.m1 // Works
trait Y[A] {
def m2: Unit
}
implicit def toY[T, A](x: T)(implicit toX: T => X[A]): Y[A] = ???
f.m2 // Won't compile
Unfortunately, the last line won't compile.
Doing any one of the following changes is enough to make the code compile:
- Turning
X
non-generic - Turning
Y
non-generic - Replacing the source type (which is a function generic on the input type) with a function generic on the output type (
Int => A
) - Replacing the source type with other generic types such as
Option[A]
,Seq[A]
orArray[A]
Based on this, my conclusion is that the chain of implicit conversions won't work because the source type (function generic on the input type) is generic and contravariant and the intermediate and target types (X[A]
and Y[A]
) are generic.
Any ideas on how to solve this?
UPDATE: The final code is indented to handle not only a function as a source type, by other types as well (Option[A]
, Seq[A]
, A
, etc.). To achieve this, the idea is to have versions of toX
function that convert each of these types to X[A]
. Then only one version of toY
is desired.
I think i have a solution for you problem, check out the following code:
I am using here higher kinded type syntax. It's advanced feature of scala language and i am not expirienced enough to explain it properly. Conversion toY should work for any type that takes exactly two type parameters, (and has defined conversion "toX").
Question is do you really need conversion toY to be generic on parameter T? Maybe it is enough for it to accept functions as arguments:
You can read more about higher kinded types, for example this post:
Scala: Types of a higher kind
Update
Following question author demands i came up with the following solution:
It is still not the best solution as it is needed to provide 3 (or even more) methods that technically do the the same thing, i don't know how to generify it, nor if it is possible in the first place.