2016-12-18 7 views
4

그래서 저는 약간 놀아 실재론과 분산에 대해 글을 쓰려고했습니다. 흥미로운 코드 조각을 보았습니다.컴파일러가 V [+ _]에 대해 V [U] <: T => V (U <V <_ : U) => (_ <: V [_ <: U]

final case class Box[+T](val value: T) { 
    def >>=[U](f: T => Box[U]) = f(value) 
    def flatMap[U](f: (_ >: T) => (_ <: Box[_ <: U])): Box[U] = this >>= f 
} 

이것은 컴파일에 실패 :

(_ >: T) => (_ <: Box[_ <: U])T => Box[U]의 하위 유형 아니므로 내가 이상한 찾아
Variance.scala:3: no type parameters for method >>=: (f: T => Box[U])Box[U] exist so that it can be applied to arguments (_$1 => _$2) 
--- because --- 
argument expression's type is not compatible with formal parameter type; 
found : _$1 => _$2 where type _$2 <: Box[_ <: U], type _$1 >: T 
required: T => Box[?U] 
    def flatMap[U](f: (_ >: T) => (_ <: Box[_ <: U])): Box[U] = this >>= f 
                   ^
Variance.scala:3: type mismatch; 
found : _$1 => _$2 where type _$2 <: Box[_ <: U], type _$1 >: T 
required: T => Box[U] 
    def flatMap[U](f: (_ >: T) => (_ <: Box[_ <: U])): Box[U] = this >>= f 
                    ^

? Function1은 첫 번째 형식 매개 변수에서 반올림 적이므로 T => (_ <: Box[_ <: U])의 하위 유형입니다. Function1은 결과 유형에서 공 변하기 때문에 T => Box[_ <: U]의 하위 유형이고 Box은 매개 변수가 공 변하기 때문에 T => Box[U]의 하위 유형 전체가 아닌가?

이상하게 타입 귀속에 "힌트"f: T => Box[U]가 컴파일 만드는 컴파일러

// This change is not required ;) 
type Box[T] = `What A Category Theorist Calls "The Identity Monad" And What Everyone Else Calls "A Box"`[T] 
final case class `What A Category Theorist Calls "The Identity Monad" And What Everyone Else Calls "A Box"`[+T](val value: T) { 
    def >>=[U](f: T => Box[U]) = f(value) 
    def flatMap[U](f: (_ >: T) => (_ <: Box[_ <: U])): Box[U] = this >>= (f: T => Box[U]) 
} 

에 코드를 변경. 암묵적인 변환이나 변수 선언이 없으므로 아무런 차이가 없어야합니다.

이 날 문제가 덜 컴파일러가 힘든 시간이 할 수없는 (_ >: T) => (_ <: Box[_ <: U]) <: T => Box[U] 것을 더와 함께 점점을 갖는이라고 생각한다

def flatMap[U](f: (_ >: T) => (_ <: Box[_ <: U])): Box[U] = this.>>=[U](f) 

를 쓰고 내가 컴파일이 점점 발견 다른 방법 오류 메시지가 암시하는 것으로 보이는 >>=의 type 매개 변수를 유추합니다.

(SBT와 스칼라 2.12.1를 (사용, 그 아무것도 변경하는 경우))

답변

0
final case class Box[+T](val value: T) { 
    def >>=[U](f: T => Box[U]) = f(value) 
    def flatMap[U](f: (_ >: T) => (_ <: Box[_ <: U])): Box[U] = this >>= f 
} 

flatMap retrun 유형은 Box[U]하지만, this >>= f을 사용합니다.

따라서 >>=f 유형 (_ >: T) => (_ <: Box[_ <: U])으로 자동 변경됩니다.

so Box[(_ >: T) => (_ <: Box[_ <: U])]이 일치하지 않습니다. Box[U].

난 당신이 그런 식으로 변경할 수 있다고 생각 :
def flatMap[U](f: (_ >: T) => (_ <: Box[_ <: U])): Box[U] = this >>=[U] f

+0

내가 코드가 작동을 만드는 방법을 알고; '_ <: Box [_ <: U]'*는'Box [U]'와 일치해야하기 때문에 * 왜 * 수정해야하는지 묻고 있습니다. 나는'[U]'를'>> ='에 추가하면 컴파일된다는 것을 알고있다. – HTNW

+0

이유는'Box [(_> : T) =] (_ <: 상자 [_ <: U]) ''일치하지 않습니다'상자 [U]' –

+0

상자 { T) => (_ <: Box [_ <: U])]'? – HTNW