简体   繁体   English

HList上的映射在Scala&Shapeless中失败,具有泛型类型的子类型

[英]Map on HList fails with subtypes of generic type in Scala & Shapeless

Say we have the following classes and some values (in Scala): 假设我们有以下类和一些值(在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 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, 你最好的选择是@ TravisBrown建议使用视图绑定,

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. 无形状的多态函数值不太可能被更改为直接支持使初始定义按照您的需要工作所需的参数类型方差的类型,因为这会与(非常理想的IMO)非常精确地区分类型特定情况的能力相冲突。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM