Weird behavior trying to convert case classes to heterogeneous lists recursively with Shapeless

前端 未结 2 974
[愿得一人]
[愿得一人] 2020-11-28 10:59

I stayed up way too late last night trying to figure out this Shapeless issue and I\'m afraid it\'s going to eat my evening if I don\'t get it off my chest, so here goes.

2条回答
  •  猫巷女王i
    2020-11-28 11:11

    I took a slightly different approach.

    trait CaseClassToHList[X] {
      type Out <: HList
    }
    
    trait LowerPriorityCaseClassToHList {
      implicit def caseClass[X](implicit gen: Generic[X]): CaseClassToHList[X] {
        type Out = generic.Repr
      } = null
    }
    
    object CaseClassToHList extends LowerPriorityCaseClassToHList {
      type Aux[X, R <: HList] = CaseClassToHList[X] { type Out = R }
    
      implicit def caseClassWithCaseClasses[X, R <: HList](
        implicit toHList: CaseClassToHList.Aux[X, R],
        nested: DeepHLister[R]): CaseClassToHList[X] {
        type Out = nested.Out
      } = null
    }
    
    trait DeepHLister[R <: HList] {
      type Out <: HList
    }
    
    object DeepHLister {
    
      implicit def hnil: DeepHLister[HNil] { type Out = HNil } = null
    
      implicit def caseClassAtHead[H, T <: HList](
        implicit head: CaseClassToHList[H],
        tail: DeepHLister[T]): DeepHLister[H :: T] {
        type Out = head.Out :: tail.Out
      } = null
    
      def apply[X <: HList](implicit d: DeepHLister[X]): d.type = null
    }
    

    Tested with the following code:

    case class A(x: Int, y: String)
    case class B(x: A, y: A)
    case class C(b: B, a: A)
    case class D(a: A, b: B)
    
    object Test {
    
      val z = DeepHLister[HNil]
      val typedZ: DeepHLister[HNil] {
        type Out = HNil
      } = z
    
      val a = DeepHLister[A :: HNil]
      val typedA: DeepHLister[A :: HNil] {
        type Out = (Int :: String :: HNil) :: HNil
      } = a
    
      val b = DeepHLister[B :: HNil]
      val typedB: DeepHLister[B :: HNil] {
        type Out = ((Int :: String :: HNil) :: (Int :: String :: HNil) :: HNil) :: HNil
      } = b
    
      val c = DeepHLister[C :: HNil]
      val typedC: DeepHLister[C :: HNil] {
        type Out = (((Int :: String :: HNil) :: (Int :: String :: HNil) :: HNil) :: (Int :: String :: HNil) :: HNil) :: HNil 
      } = c
    
      val d = DeepHLister[D :: HNil]
      val typedD: DeepHLister[D :: HNil] {
        type Out = ((Int :: String :: HNil) :: ((Int :: String :: HNil) :: (Int :: String :: HNil) :: HNil) :: HNil) :: HNil
      } = d
    }
    

提交回复
热议问题