2017-02-03 4 views
2

나는 그 HList 형식 매개 변수의 첫 번째 두 개의 필드가 5까지 추가되도록 typeclass, SumEq5, 쓰기를 시도 :Nat의 합계에 대한 컴파일 타임 확인?

trait SumEq5[A] 
object SumEq5 { 
    def apply[L <: HList](implicit ev: SumEq5[L]): SumEq5[L] = ev 

    implicit def sumEq5Ev[L <: HList, A <: Nat, B <: Nat](
    implicit hcons: IsHCons.Aux[L, A, B :: HNil], 
      ev: Sum.Aux[A, B, _5] 
): SumEq5[L] = new SumEq5[L] {} 
} 

을하지만 작동하는 것처럼하지 않습니다

import shapeless._ 
import shapeless.nat._ 
import net.SumEq5 

scala> SumEq5[_0 :: _5 :: HNil] 
<console>:19: error: could not find implicit value for 
    parameter ev: net.SumEq5[shapeless.::[shapeless.nat._0,shapeless.:: 
     [shapeless.nat._5,shapeless.HNil]]] 
     SumEq5[_0 :: _5 :: HNil] 

주십시오 왜 _0 :: _5 :: HNil에 2 개의 Nat이 5와 같은지에 대한 암시가 있습니다.

EDIT

Denis Rosca의 도움말에 대한 질문은 shapeless's gitter으로 업데이트되었습니다.

+0

형질이 비어, 추가 증인없이 다시, (오히려 정확히 두 이상) 요소를 적어도 두 사람과 함께 HList의 수용이 일반화, 그래서 왜 그냥'수 새로운 SumEq5 [L]'? – cchantep

+0

괜찮 았지만 내 입력에는 작동하지 않을 수 있습니까? –

답변

3
데일 Wijnand 마커스 헨리가 가리키는된다

올바른 방향으로 당신이 당신이 정말로 두 요소 HList의를 수용하려는 그러나 경우에, 임의의 길이의 HList들에 일반화하려는 경우, 다음 여기

scala> import shapeless._, nat._, ops.nat._ 
import shapeless._ 
import nat._ 
import ops.nat._ 

scala> :paste 
// Entering paste mode (ctrl-D to finish) 

trait SumEq5[A] 

object SumEq5 { 
    def apply[L <: HList](implicit ev: SumEq5[L]): SumEq5[L] = ev 

    implicit def sumEq5AB[A <: Nat, B <: Nat] 
    (implicit ev: Sum.Aux[A, B, _5]): SumEq5[A :: B :: HNil] = 
     new SumEq5[A :: B :: HNil] {} 
} 

// Exiting paste mode, now interpreting. 

defined trait SumEq5 
defined object SumEq5 

scala> SumEq5[_0 :: _5 :: HNil] 
res0: SumEq5[_0 :: _5 :: HNil]] = [email protected] 

가장 큰 차이점은 그이다, 오히려 간단한 해결책이다 인스턴스는 명시 적으로 de이다. 목록에 정확히 2 개의 요소가 있다는 증거가 있다는 조건하에, 일반적으로 목록에 대해 정의되기보다는 두 개의 요소 목록에 대해 벌금이 부과됩니다. 데일의 갱신에 따라

, 우리는

scala> import shapeless._, nat._, ops.nat._ 
import shapeless._ 
import nat._ 
import ops.nat._ 

scala> :paste 
// Entering paste mode (ctrl-D to finish) 

trait SumEq5[A] 

object SumEq5 { 
    def apply[L <: HList](implicit ev: SumEq5[L]): SumEq5[L] = ev 

    implicit def sumEq5AB[A <: Nat, B <: Nat, T <: HList] 
    (implicit ev: Sum.Aux[A, B, _5]): SumEq5[A :: B :: T] = 
     new SumEq5[A :: B :: T] {} 
} 

// Exiting paste mode, now interpreting. 

defined trait SumEq5 
defined object SumEq5 

scala> SumEq5[_0 :: _5 :: HNil] 
res0: SumEq5[_0 :: _5 :: HNil]] = [email protected] 
+0

사실, 훨씬 간단합니다. 그래도이 아이디어는 2 개 이상의 요소가있는 HList를 처리하는 것이고 그 중 처음 두 개가 합계가 5 인 것으로 가정합니다. –

+0

해당 사례를 캡처하기 위해 업데이트되었습니다. –

+0

오, 그래, 이런. 케빈, 네 대답이 여기 있네. –

3

원본이 의도 한대로 작동하지 않는 이유를 알지 못하는 부분 해답 (예 : 해결 방법) 만 제공합니다.

당신이 IsHCons.Aux[L, A, B :: HNil] 직접 요청할 수없는 것 같은데, 당신은 단편을 수행해야합니다

  1. IsHCons.Aux[L, A, L2], 따라서 다음
  2. IsHCons.Aux[L2, B, HNil]

을,이 컴파일 :

import shapeless._, nat._, ops.hlist._, ops.nat._ 

trait SumEq5[A] 
object SumEq5 { 
    def apply[L <: HList](implicit ev: SumEq5[L]): SumEq5[L] = ev 

    implicit def sumEq5Ev[L <: HList, L2 <: HList, A <: Nat, B <: Nat](
    implicit hcons0: IsHCons.Aux[L, A, L2], 
      hcons: IsHCons.Aux[L2, B, HNil], 
      ev: Sum.Aux[A, B, _5] 
): SumEq5[L] = new SumEq5[L] {} 
} 

object T { 
    def main(args: Array[String]): Unit = { 
    SumEq5[_0 :: _5 :: HNil] 
    } 
} 

Miles Sabin's answer에서 다음 는

, 이것은과 같이 처음 두의 합계가 5로되어있는 2 개 이상의 요소 중 어느 HList을 지원하기 위해 약간 변형 될 수있다 :

import shapeless._, nat._, ops.hlist._, ops.nat._ 

trait SumEq5[A] 
object SumEq5 { 
    def apply[L <: HList](implicit ev: SumEq5[L]): SumEq5[L] = ev 

    implicit def sumEq5Ev[L1 <: HList, L2 <: HList, L3 <: HList, A <: Nat, B <: Nat](
    implicit hcons1: IsHCons.Aux[L1, A, L2], 
      hcons2: IsHCons.Aux[L2, B, L3], 
      ev: Sum.Aux[A, B, _5] 
): SumEq5[L1] = new SumEq5[L1] {} 
} 

object T { 
    def main(args: Array[String]): Unit = { 
    SumEq5[_0 :: _5 :: HNil] 
    } 
} 
+2

사람들이 처음에 재귀 적 또는 회귀 적 유형의 작업을 배울 때 많이 봅니다. 컴파일러는 단계별로 진행해야합니다. Kevin, A :: B :: HNil에 대한 인스턴스를 얻으려고합니다. 먼저 HNil에 대한 인스턴스가 없어도 B :: HNil에 대한 인스턴스가 있어야합니다. 이 솔루션은 IsHCons 계층을 하나 더 추가하여 귀납적 프로세스의 필요성을 회피합니다. 유도 적으로하려면 B :: HNil이 _5보다 작거나 같음을 증명해야합니다. 그러면 A :: B :: HNil은 두 개의 암시 적 정의에서 평등합니다. –

+0

감사합니다, Dale and Marcus! 이 답변과 의견을 통해 나는 더 많은 것을 배울 수있었습니다. –