簡體   English   中英

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

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

假設我們有以下類和一些值(在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)

此外,我們定義以下多態函數值(使用無形):

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

現在我們可以致電:

f(x1); f(x2); f(x3); f(x4)

哪一切都成功了(應該恕我直言)。 然而:

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)

UPDATE

似乎如果我們分別指定每個案例,那很好:

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

然而,試圖表達這一點更聰明,不起作用(甚至對於簡單的應用程序):

object f extends Poly1 {
  implicit def caseA[T, S <: A[T]] = at[S]{s => Some(s.x)}
}

你最好的選擇是@ TravisBrown建議使用視圖綁定,

object f extends Poly1 {
  implicit def caseA[T, S <% A[T]] = at[S]{s => Some(s.x)}
}

或者,或多或少等價地,類型約束,

object f2 extends Poly1 {
  implicit def caseA[S, T](implicit ev : S <:< A[T]) = at[S]{s => Some(s.x)}
}

或者你的兩個案例解決方案的一個變化,它會影響共性,

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

無形狀的多態函數值不太可能被更改為直接支持使初始定義按照您的需要工作所需的參數類型方差的類型,因為這會與(非常理想的IMO)非常精確地區分類型特定情況的能力相沖突。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM