Say we have the following classes and some values (in Scala):
class A[T](val x: T)
class B[T](x: T, val y: T) extends A[T](x)
val x1 = new A("test")
val x2 = new B(1,2)
val x3 = new B("foo","bar")
val x4 = new A(1)
Further, we define the following polymorphic function value (using shapeless):
object f extends (A ~> Option) {
def apply[T](s: A[T]) = Some(s.x)
}
Now we can call:
f(x1); f(x2); f(x3); f(x4)
Which all succeed (and should IMHO). However:
val list = x1 :: x2 :: x3 :: x4 :: HNil
list.map(f)
// could not find implicit value for parameter mapper:
// shapeless.Mapper[f.type,shapeless.::[A[String],shapeless.::[
// B[Int],shapeless.::[B[String],shapeless.::[A[Int],shapeless.HNil]]]]]
Where I was expecting:
Some("test") :: Some(1) :: Some("foo") :: Some(1) :: HNil
Note that this works:
val list2 = x1 :: x4 :: HNil // only instances of A
list2.map(f)
UPDATE
It seems that if we specify each case separately, it's fine:
object f extends Poly1 {
implicit def caseA[T] = at[A[T]]{s => Some(s.x)}
implicit def caseB[T] = at[B[T]]{s => Some(s.x)}
}
However, trying to express this a bit smarter, does not work (not even for simple applications):
object f extends Poly1 {
implicit def caseA[T, S <: A[T]] = at[S]{s => Some(s.x)}
}
Your best options are one of @TravisBrown's suggestion to use a view bound,
object f extends Poly1 {
implicit def caseA[T, S <% A[T]] = at[S]{s => Some(s.x)}
}
or, more or less equivalently, a type constraint,
object f2 extends Poly1 {
implicit def caseA[S, T](implicit ev : S <:< A[T]) = at[S]{s => Some(s.x)}
}
or a variation on your two case solution which factors out the commonality,
object f3 extends Poly1 {
def asub[T](s: A[T]) = Some(s.x)
implicit def caseA[T] = at[A[T]](asub)
implicit def caseB[T] = at[B[T]](asub)
}
It's unlikely that shapeless's polymorphic function values will be changed to directly support the kind of argument type variance needed to make the initial definition work as you wanted, because that would conflict with the (highly desirable IMO) ability to discriminate type-specific cases very precisely.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With