2017-02-13 3 views
4

다음 예제에서는 Scaffile 컴파일러가 Wrapper의 상위 형식 표현을 사용하도록 정의 된 경우에만 암시 적 클래스를 인식하는 것으로 보입니다. 왜 그런가요?매개 변수화 된 형식의 암시 적 클래스 해결

scala> case class Nested(n: Int) 
defined class Nested 

scala> case class Wrapper[A <: Product](nested: A) 
defined class Wrapper 

scala> implicit class I1[W <: Wrapper[A], A <: Product](underlying: W) { 
    | def ok1() = true 
    | } 
defined class I1 

scala> Wrapper(Nested(5)).ok1() 
<console>:26: error: value ok1 is not a member of Wrapper[Nested] 
     Wrapper(Nested(5)).ok1() 
         ^
scala> implicit class I2[W <: Wrapper[_]](underlying: W) { 
    | def ok2() = true 
    | } 
defined class I2 

scala> Wrapper(Nested(5)).ok2() 
res1: Boolean = true 

예를 들어, TypeTag, 그것은에 부착 할 증거 typeclass 수 있도록 중첩 된 유형에 대한 전체 정보를 유지 관리 암시 해상도에 대한 해결 방법이 있나요?

참고 : 위의 예는 사례 클래스가 될 NestedWrapper을 보여 주지만 질문에 필수적인 것은 아닙니다. 더 짧고 간단한 콘솔 세션의 편의성 일뿐입니다.

+0

'I1'은별로 도움이되지 않습니다. 'A <: Product'에 대한 타입 제약이 이미 존재합니다. 왜 암시 적 변환에서 그것을 복제합니까? – cchantep

+0

@cchantep 어떻게 암시 적으로'A'의 세부 사항을 알 수 있습니까? 예를 들어,'TypeTag'을 암시 적으로 연관시킬 수 있습니까? – Sim

답변

4

이것은 스칼라 유형 유추의 한계 때문에 발생합니다. SI-2272을 참조하십시오.

컴파일러가 A을 제대로 추론 할 수 없으므로 암시 적으로 해결되지 않습니다. -Xlog-implicits을 사용하면 이것을 볼 수 있습니다. ANothing으로 추정되는 알 수 있습니다 :

I1 is not a valid implicit value for Test.w.type => ?{def ok: ?} because: 
inferred type arguments [Wrapper[Nested],Nothing] do not conform to method I1's type parameter bounds [W <: Wrapper[A],A <: Product] 

같은 일이 발생 우리가 수동으로 I1를 인스턴스화하려고하면 : 이제

scala> val w = Wrapper(Nested(5)) 
w: Wrapper[Nested] = Wrapper(Nested(5)) 

scala> new I1(w) 
<console>:21: error: inferred type arguments [Wrapper[Nested],Nothing] do not conform to class I1's type parameter bounds [W <: Wrapper[A],A <: Product] 
     new I1(w) 
    ^
<console>:21: error: type mismatch; 
found : Wrapper[Nested] 
required: W 
     new I1(w) 
      ^

, 워크 어라운드.

먼저 Wrapper이 사례 클래스이므로 이 하위 유형을 포함하는 이유가되어서는 안됩니다. 당신은 W 유형의 매개 변수를 제거하고, Wrapper[A]underlying을 변경할 수 있습니다 제거하는 동안, W <:< Wrapper[A] 것을 당신은 또한 요구할 수, 암시 적 증거를 여전히 두 가지 유형 매개 변수를 필요로 할 경우

implicit class I1[A <: Product](underlying: Wrapper[A]) { 
    def ok = true 
} 

상단 바인딩 유형에 매개 변수 W :

implicit class I1[W, A <: Product](underlying: W)(implicit ev: W <:< Wrapper[A]) { 
    def ok = true 
} 
+0

'-Xlog-implicits'는 좋은 팁입니다. – Sim

1

마이클이 말한 모든 것이 사실입니다. 이 문제에 대한 몇 가지 추가적인 관점이 있습니다.

암시 적 클래스를 작성한 방법 때문에 암시 적 클래스가 Wrapper의 모든 하위 유형에서 작동하고 가능하면 관련된 모든 유형에 대한 구체적인 정보를 갖고있는 것처럼 보입니다. (99 %는 사례 클래스를 확장하는 것이 좋지 않을 수도 있지만 가능하며 이러한 비결은 비 케이스 클래스에서도 작동합니다).

트릭은 기본적으로 입니다. 유추하려는 모든 유형 매개 변수가 값 매개 변수 목록의 어딘가에 있는지 확인하십시오.

scala> trait Foo[A]; trait Bar extends Foo[Int] 
defined trait Foo 
defined trait Bar 

scala> implicitly[Bar with Foo[Int] =:= Bar] 
res0: =:=[Bar with Foo[Int],Bar] = <function1> 

지식의 두 조각을 가지고이처럼 암시 클래스를 다시 작성할 수 있습니다 :

implicit class I1[Y, A <: Product](underlying: Y with Wrapper[A]) { 
    def ok1(): (Y, A) = ??? 
} 

을 그리고 직장에서 그것을 볼 :

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

case class Nested(n: Int) 
case class Wrapper[A <: Product](nested: A) 
class Crazy(override val nested: Nested) extends Wrapper[Nested](nested) 

implicit class I1[Y, A <: Product](underlying: Y with Wrapper[A]) { 
    def ok1(): (Y, A) = ??? 
} 

// Exiting paste mode, now interpreting. 


scala> :type Wrapper(Nested(5)).ok1() 
(Wrapper[Nested], Nested) 

scala> :type new Crazy(Nested(5)).ok1() 
(Crazy, Nested) 
명심해야 할 또 다른 점은 이것이다

Michael이 준 마지막 해결책은 동일한 것을 기반으로합니다. 즉, 상한값을 암시 적 매개 변수 목록으로 이동하면 A이 value 매개 변수 목록에 나타나고 컴파일러에 의해 추론 될 수있다.

+0

추가 컨텍스트가 유용합니다. – Sim

관련 문제