HList 上的映射在 Scala & 中因泛型类型的子类型而失败无形 [英] Map on HList fails with subtypes of generic type in Scala & Shapeless

查看:48
本文介绍了HList 上的映射在 Scala & 中因泛型类型的子类型而失败无形的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我们有以下类和一些值(在 Scala 中):

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)

此外,我们定义了以下多态函数值(使用 shapeless):

Further, we define the following polymorphic function value (using shapeless):

object f extends (A ~> Option) {
  def apply[T](s: A[T]) = Some(s.x)
}

现在我们可以调用:

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]]]]]

我期待的地方:

Some("test") :: Some(1) :: Some("foo") :: Some(1) :: HNil

请注意,这是有效的:

val list2 = x1 :: x4 :: HNil // only instances of A
list2.map(f)

更新

看来,如果我们分别指定每个 case 就好了:

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)}
}

推荐答案

你最好的选择之一是@TravisBrown 建议使用视图边界,

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)
}

shapeless 的多态函数值不太可能被更改为直接支持使初始定义按您想要的方式工作所需的参数类型变化类型,因为这会与(非常理想的 IMO)区分类型特定的能力相冲突案例非常准确.

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.

这篇关于HList 上的映射在 Scala &amp; 中因泛型类型的子类型而失败无形的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆