복붙노트

[SCALA] 볼품에 반복적으로 이기종 목록에 케이스 클래스를 변환하려고 이상한 행동

SCALA

볼품에 반복적으로 이기종 목록에 케이스 클래스를 변환하려고 이상한 행동

나는이 볼품없는 문제를 알아 내려고 지난 밤에 너무 늦게 방법을 체재하고 나는 내 가슴을 하차하지 않으면 내 저녁을 먹을 것 걱정, 그래서 여기에 표시됩니다.

이 최소화 버전에서는 그냥 반복적으로 이기종 목록으로 케이스 클래스를 변환하는 타입의 클래스를 정의하고 있습니다 :

import shapeless._

trait DeepHLister[R <: HList] extends DepFn1[R] { type Out <: HList }

trait LowPriorityDeepHLister {
  type Aux[R <: HList, Out0 <: HList] = DeepHLister[R] { type Out = Out0 }

  implicit def headNotCaseClassDeepHLister[H, T <: HList](implicit
    dht: DeepHLister[T]
  ): Aux[H :: T, H :: dht.Out] = new DeepHLister[H :: T] {
    type Out = H :: dht.Out
    def apply(r: H :: T) = r.head :: dht(r.tail)
  }
}

object DeepHLister extends LowPriorityDeepHLister {
  implicit object hnilDeepHLister extends DeepHLister[HNil] {
    type Out = HNil
    def apply(r: HNil) = HNil
  }

  implicit def headCaseClassDeepHLister[H, R <: HList, T <: HList](implicit
    gen: Generic.Aux[H, R],
    dhh: DeepHLister[R],
    dht: DeepHLister[T]
  ): Aux[H :: T, dhh.Out :: dht.Out] = new DeepHLister[H :: T] {
    type Out = dhh.Out :: dht.Out
    def apply(r: H :: T) = dhh(gen.to(r.head)) :: dht(r.tail)
  }

  def apply[R <: HList](implicit dh: DeepHLister[R]): Aux[R, dh.Out] = dh
}

현실을 사용해보십시오! 먼저 우리는 몇 가지 경우 클래스가 필요합니다 :

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)

그리고 (나는이 완전히 읽을 수 엉망 없다는 위해서 유형 구문을 정리 한 참고)

scala> DeepHLister[A :: HNil]
res0: DeepHLister[A :: HNil]{
  type Out = (Int :: String :: HNil) :: HNil
} = DeepHLister$$anon$2@634bf0bf

scala> DeepHLister[B :: HNil]
res1: DeepHLister[B :: HNil] {
  type Out = (
    (Int :: String :: HNil) :: (Int :: String :: HNil) :: HNil
  ) :: HNil
} = DeepHLister$$anon$2@69d6b3e1

scala> DeepHLister[C :: HNil]
res2: DeepHLister[C :: HNil] {
  type Out = (
    ((Int :: String :: HNil) :: (Int :: String :: HNil) :: HNil) ::
    (Int :: String :: HNil) ::
    HNil
  ) :: HNil
} = DeepHLister$$anon$2@4d062faa

여태까지는 그런대로 잘됐다. 하지만:

scala> DeepHLister[D :: HNil]
res3: DeepHLister[D :: HNil] {
  type Out = ((Int :: String :: HNil) :: B :: HNil) :: HNil
} = DeepHLister$$anon$2@5b2ab49a

B 조 변환되지 않았다. 우리가 -Xlog-implicits 켜면이 마지막 메시지입니다 :

<console>:25: this.DeepHLister.headCaseClassDeepHLister is not a valid implicit value for DeepHLister[shapeless.::[B,shapeless.HNil]] because:
hasMatchingSymbol reported error: diverging implicit expansion for type DeepHLister[this.Repr]
starting with method headNotCaseClassDeepHLister in trait LowPriorityDeepHLister
              DeepHLister[D :: HNil]
                         ^

ME-headCaseClassDeepHLister 이해가되지 않는 것은 DeepHLister 생성 할 수 있어야 어느 [B를 :: HNil] 잘, 당신은 직접 물어 경우가 않습니다.

이 2.10.4 및 2.11.2 및 2.0.0 릴리스와 마스터 모두 모두에서 발생합니다. 나는이 버그가 수 있도록이 있는지 꽤 있어요,하지만 난 뭔가 잘못하고 있어요 가능성을 배제하고 있지 않다. 사람이 전에 이런 것을 본 적이 있습니까? 내 논리 또는 내가 부족 일반에 대한 몇 가지 제한 사항이이 뭔가 잘못인가?

좋아요, 감사에 대한 청취 - 어쩌면 지금은 책이나 뭔가를 읽어 갈 수 있습니다.

해결법

  1. ==============================

    1.이제이 더 많거나 적게 최근 무형의-2.1.0-SNAPSHOT을 사용하여 작성된로 작동 구축하고,이 문제의 샘플의 가까운 친척을 예로 들어이 추가되었습니다.

    이제이 더 많거나 적게 최근 무형의-2.1.0-SNAPSHOT을 사용하여 작성된로 작동 구축하고,이 문제의 샘플의 가까운 친척을 예로 들어이 추가되었습니다.

    원래의 문제는 일반의 각 확장은 원칙적으로 관련되는 HList 유형을 생산할 수의 DeepHLister 타입의 클래스 인스턴스의 암시 해상도에 새로운 HList 유형을 소개하고 있다는 것입니다하지만시 이전에 본 어떤 종류보다 더 복잡 동일한 해상도. 이 조건은 발산 검사기를 여행하고 확인 프로세스를 중단합니다.

    이 D에 대한하지만 C는 대략적인 근사치로, 스칼라의 typechecker의 구현의 세부 사항에 숨어 있지만에 대한 발생 이유의 정확한 세부 사항은 차별화 C의 해상도 동안 우리는 A 전에 B를 (더)를 참조하십시오이다 발산 검사기가 우리의 유형을 수렴하는 행복 그래서 (작은); 반대로 D의 해상도 중 우리가 전에 B는 A를 (작은) 참조 (큰) 발산 검사기 (보수적) 보석금 그래서.

    엉성한 2.1.0에서 이에 대한 수정이 최근 개선 된 레이지 형 생성자와 관련된 암시 매크로 인프라. 이 차이를 통해 더 많은 사용자가 제어 할 수 있으며, 재귀 유형에 자동으로 파생 형 클래스 인스턴스 할 수있는 기능에 매우 중요하다 재귀 암시 값을 구성하는 암시 적 해상도의 사용을 지원합니다. 이 많은 예는 무형의 코드베이스에서 찾을 수 있습니다 특히 재 작업 유형 클래스 파생 인프라와 스크랩 더 이상 전용 매크로 지원을 필요로하지만, 일반 및 게으른 프리미티브의 측면에서 완전히 구현 귀하의 상용구의 구현입니다. 이러한 메커니즘의 다양한 응용 프로그램은 무형의 예 하위 프로젝트에서 찾을 수 있습니다.

  2. ==============================

    2.나는 약간 다른 접근 방식을했다.

    나는 약간 다른 접근 방식을했다.

    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
    }
    

    다음 코드로 테스트 :

    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
    }
    
  3. from https://stackoverflow.com/questions/25923974/weird-behavior-trying-to-convert-case-classes-to-heterogeneous-lists-recursively by cc-by-sa and MIT license