2014-04-24 2 views
1

이기종 기본 유형을 그룹화하기위한 일반 래퍼 문제를 다시 검토합니다. 나는 형의 멤버를 사용하고, 이제 구조는 다음과 같습니다가변 유형 검사/패턴 일치 (가변 유형 유형 포함)

trait Outer[S] { 
    type A1 
    def inner: Inner[S] { type A = A1 } 
} 

trait Inner[S] { 
    type A 
    def peer: A 
} 

물론 특정 개체를 테스트하는 것입니다 다음 문제, 예를 들면 :

def test[S](o: Outer[S]): Option[Outer[S] { type A1 = String }] = o match { 
    case os: Outer[S] { type A1 = String } => Some(os) 
    case _ => None 
} 

이 때문에 유형이 작동하지 않습니다 지워 없앰. 문제는 피어에 대해 형식 매개 변수를 추상화해야한다는 것입니다. 즉 하나의 형식 매개 변수 [S]을 가진 (대부분의) 피어가 있지만 다른 피어에는 없습니다. 따라서 Inner 및/또는 Outer에 대한 형식 생성자 매개 변수를 사용하는 것은 적합하지 않습니다.

싼 솔루션은 실제 하위 클래스를 필요로하는 것입니다

trait StringOuter[S] extends Outer[S] { type A1 = String } 

def test1[S](o: Outer[S]): Option[Outer[S] { type A1 = String }] = o match { 
    case os: StringOuter[S] => Some(os) 
    case _ => None 
} 

을하지만 다른 동료을 많이 가지고 있기 때문에 나는이 솔루션을 좋아하지 않아, 나는 전용 랩퍼를 작성하지 않으 각자의 수업. 또한 예를 들어, 이러한 모든 하위 클래스에 복사 메서드를 작성해야한다면 이러한 개체를 복사하는 것이 짜증나게됩니다.

아마도 클래스 태그가 남았습니까?

trait Foo[S] 
type Inner1[S] = Inner[S] { type A = Foo[S] } 
type Inner2[S] = Inner[S] { type A = String } 

: 나는 다른 종류의 매개 변수 arity에 다음과 같은 두 피어 유형이있는 경우 이것은 어떻게 해결 될 것인가? 우리가 잠시 일치하는 패턴에 대해 잊어 버린 경우

답변

0

덕분에 삭제를 입력, 시간이 주위에 조롱 한 후,이 유일하게 가능한 솔루션입니다. 플랫 클래스와 불변 타입을 고수하십시오. 공변 유형과 패턴 매칭의 시나리오는 잊어라.

0

, 하나는 어느 정도 보통 오래된 반사를 사용할 수 있습니다

import reflect.ClassTag 

trait Outer[S] { 
    type A1 
    def inner: Inner[S] { type A = A1 } 
    def as[A](implicit tag: ClassTag[A]): Option[Outer[S] { type A1 = A }] = 
    inner.peer match { 
     case _: A => Some(this.asInstanceOf[Outer[S] { type A1 = A }]) 
     case _ => None 
    } 
} 

trait Inner[S] { 
    type A 
    def peer: A 
} 

테스트 :

trait Foo[S]  

val x = new Outer[Unit] { 
    type A1 = String 
    val inner = new Inner[Unit] { 
    type A = String 
    val peer = "foo" 
    } 
} 

val y = new Outer[Unit] { 
    type A1 = Foo[Unit] 
    val inner = new Inner[Unit] { 
    type A = Foo[Unit] 
    val peer = new Foo[Unit] {} 
    } 
} 

val xs = x.as[String] 
val xi = x.as[Foo[Unit]] 

val ys = y.as[String] 
val yi = y.as[Foo[Unit]] 

유일한 문제는 이제 더 높은 kinded이다 유형이 확인되지 않습니다

y.as[Foo[Nothing]] // Some! 

또 다른 아이디어는 S 매개 변수가 항상 존재하도록 내 디자인을 변경하는 것입니다. 그런 다음

trait Sys[S <: Sys[S]] 

trait Inner[S <: Sys[S], +Elem[~ <: Sys[~]]] { 
    def peer: Elem[S] 
    def as[A[~ <: Sys[~]]](implicit tag: ClassTag[A[S]]): Option[Inner[S, A]] = 
    if (tag.unapply(peer).isDefined) 
     Some(this.asInstanceOf[Inner[S, A]]) 
    else 
     None 
} 

type In[S <: Sys[S]] = Inner[S, Any] 

trait Foo[S <: Sys[S]] { def baz = 1234 } 
trait Bar[S <: Sys[S]] 

trait I extends Sys[I] 

val i: In[I] = new Inner[I, Foo] { val peer = new Foo[I] {} } 
val j: In[I] = new Inner[I, Bar] { val peer = new Bar[I] {} } 

assert(i.as[Foo].isDefined) 
assert(i.as[Bar].isEmpty ) 
assert(j.as[Foo].isEmpty ) 
assert(j.as[Bar].isDefined) 

또는 마지막 버전이 형의 멤버 사용으로 다시 변경 :

trait Inner[S <: Sys[S]] { 
    type Elem 

    def peer: Elem 
    def as[A[~ <: Sys[~]]](implicit tag: ClassTag[A[S]]): Option[InnerT[S, A]] = 
    if (tag.unapply(peer).isDefined) 
     Some(this.asInstanceOf[InnerT[S, A]]) 
    else 
     None 
} 

type InnerT[S <: Sys[S], A[~ <: Sys[~]]] = Inner[S] { type Elem = A[S] } 


val i: Inner[I] = new Inner[I] { type Elem = Foo[I]; val peer = new Foo[I] {} } 
val j: Inner[I] = new Inner[I] { type Elem = Bar[I]; val peer = new Bar[I] {} } 

assert(i.as[Foo].isDefined) 
assert(i.as[Bar].isEmpty ) 
assert(j.as[Foo].isEmpty ) 
assert(j.as[Bar].isDefined) 

val ix: InnerT[I, Foo] = i.as[Foo].get 
ix.peer.baz 

를 ... 그것은 쉽게 변형 파괴 될 수 Serializer[Inner[S]] 같은 암시 적 해결을 위해 유리할 수있다 유형 매개 변수가 관련되어 있습니다. 다른 것을 시도

trait StringOuter[S] extends Outer[S] { type A1 = String } 

에너지의 낭비 :

관련 문제