2017-01-16 7 views
3

알려진 두 가지 다른 형식 매개 변수를 기반으로 일부 형식을 유추하도록 컴파일러를 얻으려고합니다. 여기에 예는 다음과 같습니다implicits를 사용하여 알 수없는 형식을 추론합니다.

trait ReturnCount 
trait ReturnsMany extends ReturnCount 
trait ReturnsOne extends ReturnCount 

class Query[R <: ReturnCount]{ 
    def join[R2 <: ReturnCount,R3 <: ReturnCount](q: Query[R2]): Query[R3] 
} 

당신은 내가이 읽기 쿼리 (관계가있는 성분의 세부 사항)에 가입 할 수 있도록하려면 여기에서 볼 수 있듯이. 결과로 생성되는 새 쿼리는 ReturnsOne 또는 ReturnsMany 결과를 가져 오는 쿼리 여야합니다. 해상도의 규칙도 매우 간단합니다 : 두 쿼리 모두 ReturnsOne 다음에 결합 된 쿼리 인 경우 ReturnsOne 다른 모든 경우에는 ReturnsMany입니다.

그래서 :

val q1 = new Query[ReturnsOne] 
val q2 = new Query[ReturnsMany] 
val q3 = q1 join q2 //I don't want to have 
        //to specify R3 because compiler should do it for me... 

어떻게 이것을 달성하기 위해 희망 할 수 있는가?

+0

''''''''가''''ReturnOne''' 유형이라면 질의가 리턴하는 결과의 수를 알기 위해서'''R2'''가 필요합니다. R이''''ReturnMany''' 타입이라면'''ReturnsMany'''와 같이 아무런 차이가 없을 것입니다. – shayan

+0

왜 결과가 'R2'와 'R'이 아닌가요? 'R'의 일반적인 용도는 무엇입니까? –

+0

@YuvalItzchakov R3에 의해 실제로 결정되며 R3는 결정하기 위해 R과 R2를 모두 필요로합니다. 더 구체적으로 – shayan

답변

3

이러한 3 가지 특성이 봉인 된 경우 이러한 작업을 수행하는 방법입니다. 확장 기능이 열려 있다면 아마도 더 복잡해질 것입니다.

다음과 같이 요약 할 수 있습니다. 두 가지 입력 유형이 AB이고 하나의 출력 유형이 Out 인 특성이 Fancy입니다. AB이 모두 ReturnsOne 인 경우 OutReturnsOne이되도록 암시 적 인스턴스를 정의합니다. 다른 모든 경우에는 우선 순위가 낮은 기본 사례로 되돌아갑니다. 그렇지 않으면 Out이 항상 ReturnsMany 인 경우 모호성 오류가 발생하기 때문입니다.

class Query[R <: ReturnCount] { 
    def join[R2 <: ReturnCount](q: Query[R2])(implicit fancy: Fancy[R,R2]): Query[fancy.Out] = 
    fancy.join(this, q) 
} 

This blog은 자세한 내용은 좋은 출발점이 될 수 있습니다 : 실제 시나리오에서

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

sealed trait ReturnCount 
sealed trait ReturnsMany extends ReturnCount 
sealed trait ReturnsOne extends ReturnCount 

sealed trait Fancy[A, B] { 
    type Out <: ReturnCount 
} 

object Fancy extends LowerPriority { 
    type Aux[A,B,Out1 <: ReturnCount] = Fancy[A,B] { type Out = Out1 } 

    implicit def returnsOne: Fancy.Aux[ReturnsOne,ReturnsOne,ReturnsOne] = 
    new Fancy[ReturnsOne,ReturnsOne] { type Out = ReturnsOne } 
} 

trait LowerPriority { 
    implicit def returnsMany[A,B]: Fancy.Aux[A,B,ReturnsMany] = 
    new Fancy[A,B] { type Out = ReturnsMany } 
} 

class Query[R <: ReturnCount] { 
    def join[R2 <: ReturnCount](q: Query[R2])(implicit fancy: Fancy[R,R2]): Query[fancy.Out] = ??? 
} 


// Exiting paste mode, now interpreting. 

defined trait ReturnCount 
defined trait ReturnsMany 
defined trait ReturnsOne 
defined trait Fancy 
defined object Fancy 
defined trait LowerPriority 
defined class Query 

scala> :type new Query[ReturnsOne].join(new Query[ReturnsOne]) 
Query[ReturnsOne] 

scala> :type new Query[ReturnsOne].join(new Query[ReturnsMany]) 
Query[ReturnsMany] 

scala> :type new Query[ReturnsMany].join(new Query[ReturnsMany]) 
Query[ReturnsMany] 

scala> :type new Query[ReturnsMany].join(new Query[ReturnsOne]) 
Query[ReturnsMany] 

Fancy 아마 또한 Query#join 방법 위임에 실제 구현을 포함하는 join 방법이 필요합니다 그러한 패턴들에 대해서.

+0

아름다운 R 및 R2 사용하여 R3 해결하는 암시 적 인수를 찾고 있어요. 고맙습니다 – shayan