2012-04-27 3 views
6

이 문제는 필자가 작성한 모듈에서 발생했지만 동일한 동작을 나타내는 최소한의 사례를 만들었습니다.여기에 유추가 입력되지 않는 이유는 무엇입니까?

class Minimal[T](x : T) { 
    def doSomething = x 
} 

object Sugar { 
    type S[T] = { def doSomething : T } 
    def apply[T, X <: S[T]] (x: X) = x.doSomething 
} 

object Error { 
    val a = new Minimal(4) 
    Sugar(a) // error: inferred [Nothing, Minimal[Int]] does not fit the bounds of apply 
    Sugar[Int, Minimal[Int]](a) // works as expected 
} 

문제는 컴파일러 Minimal (Int)에 내부 파라미터를 알아낼 관리이다, 그러나 명백하게 apply 일치하지 Nothing-T의 다른 발생을 설정한다. 첫 번째 매개 변수를 제거하면 두 번째 매개 변수가 제거되어 T가 정의되지 않는다고 불평하기 때문에 이들은 분명히 T과 동일합니다.

컴파일러가 첫 번째 매개 변수를 유추 할 수 없다는 모호성이 있습니까? 아니면이 버그입니까? 이 문제를 정상적으로 해결할 수 있습니까?

추가 정보 :이 코드는 구문 설탕을 시도한 간단한 예입니다. 원래의 코드는 |(a)|이 모듈이 a 인 것을 의미합니다. 여기서 a는 벡터입니다. 분명히 |(a)||[Float,Vector3[Float]](a)|을 작성하는 것보다 낫지 만, 불행히도 이것을 더 쉽게 만들려면 을 사용할 수 없습니다.

실제 오류 : 구조 유형에 대한 경계 몇 가지 불확실성이있다

inferred type arguments [Nothing,Minimal[Int]] do not conform to method apply's type parameter bounds [T,X <: Sugar.S[T]]

답변

9

이것은 Scala 컴파일러 버그는 아니지만 확실히 Scala의 유형 유추에 한계가 있습니다. 컴파일러는 X, S[T]에 대한 경계를 결정하기 전에 X을 해결하려고하지만 바인딩에는 지금까지 제약되지 않은 유형 변수 T이 언급되어 있으므로 Nothing에서 수정되고 거기에서 진행됩니다. 그것은 T을 다시 방문하지 않고 X이 완전히 해결되었습니다 ... 현재 유형 유추는 항상 이런 경우에 왼쪽에서 오른쪽으로 진행됩니다.

귀하의 예를 정확하게 실제 상황을 나타내는 경우

는,

def apply[T](x : S[T]) = x.doSomething 
다음 T

MinimalS[T]에 직접보다는 중간 경계 형의 변수를 통해 준수하도록 유추하는 간단한 수정이 있습니다.

업데이트

여호수아의 솔루션은 또한 유형 T 추론의 문제를 피할 수 있지만, 완전히 다른 방식이다. (T 더이상 X의 결합에 언급되어 있기 때문에) 행

def apply[T, X <% S[T]](x : X) = x.doSomething 

desugars,

def apply[T, X](x : X)(implicit conv : X => S[T]) = x.doSomething 

형태 변수 TX 이제 독립적으로 구해질 수 없다.즉, XMinimal으로 즉시 추론되며, 을 만족하는 X => S[T] 값의 암시 적 검색의 일부로 T이 해결됩니다. conformsscala.Predef은이 형식의 값을 제조하며 문맥 상 주어진 유형의 인수가 Minimal 인 경우 T이 Int로 유추됩니다. 이것을 스칼라에서 functional dependencies의 인스턴스로 볼 수 있습니다.

+0

예,이 솔루션은 제 경우에는 정상적으로 작동합니다. 그것은 또한 Joshua의 해결책 (미안한 Joshua!)보다 깨끗합니다. Joshua의 솔루션이 왜 작동하는지 설명 할 수 있습니까? – Dylan

+0

Joshua의 해결책이 또한 작동하는 이유에 대한 설명을 제공하는 답변이 업데이트되었습니다. –

4

, 대신 S [T]에 바인딩 된 뷰를 사용해보십시오.

def apply[T, X <% S[T]] (x: X) = x.doSomething이 정상적으로 작동합니다.

+1

위의 코드는 작동하지만 확실한 차이는 없습니다. 이 경우 뷰를 얻는 것은 수퍼 클래스로 캐스팅하는 것입니다. 그렇지 않습니까? 이것은이 수정이 컴파일러의 버그에 대한 해결 방법 일 뿐이라는 것을 의미합니까? – Dylan

+0

아, 이제 알겠습니다.'S'는 수퍼 클래스가 아닙니다. 단지보기 (의미에서)입니다. 따라서 대부분의 경우 필요하지 않더라도 뷰 바인딩이 더 적절합니다. – Dylan

관련 문제