2011-11-16 3 views
2

다음과 같이 대략적으로 달성하려고 노력 중입니다.스칼라에서 공용체 유형을 사용하는 일반 데이터 구조

/* I assume that we have some types S and T */ 

sealed trait Container[U] 
class SContainer(s: S) extends Container[S] 
class TContainer[U <: T](u: U) extends Container[U] 

/* this requires something more */ 
def invoke[U](f: String => U): Container[U] 

간단히 말하면, S 유형 또는 T의 부속 유형 인 것을 보유 할 수있는 Container 클래스가 필요합니다. Container 클래스는 컨테이너를 구성하는 데 가능한 두 가지 방법 만 있으므로이 속성을 분명히 충족시킵니다.

그러나 이제 컨테이너에 값을 래핑하는 invoke 함수를 만들려고합니다. 내 예제에서 주어진 정의는 U에 아무런 제한을 두지 않기 때문에 명확하게 작동하지 않는다.

유감스럽게도 erasure 타입 덕분에 우리는 두 개의 함수를 정의 할 수 없습니다 :

def invoke(f: String => S): Container[S] 
def invoke[U <: T](f: String => U): Container[U] 

런타임 중에는 같은 타입을 가지기 때문입니다.

invoke에 이러한 유형 제한을 표현하는 방법은 무엇입니까?

+0

. 'TContainer'는'Container [T]'의 부속 유형이되도록 정의하고,'invoke'는'Container [U]'를 반환하기를 원합니다. 먼저 컨테이너 (Container [T]) 또는 컨테이너 (Container [U])를 원할지 결정해야합니다. –

+0

와우. 당신은 틀림없이'Container [U]'이어야합니다. – andri

답변

2

다음과 같이 작동한다고 생각합니다. 나는 당신의 TS이 무엇인지 모르는, 그래서 당신은 바인딩 된 뷰 사용이

type T = AnyVal 
type S = String 

으로 노력하고있어 다음

object Container { 
    implicit def stuffS(s: S): Container[S] = new SContainer(s) 
    implicit def stuffT[U <: T](u: U): Container[T] = new TContainer(u) 
} 
sealed trait Container[U] 
case class SContainer(s: S) extends Container[S] 
case class TContainer[U <: T](u: U) extends Container[T] 

당신의 invoke가된다 :

def invoke[B, A <% Container[B]](f: String => A): Container[B] = f("hallo") 

다음 호출은 유효합니다.

invoke(_.size) // -> Container[T] = TContainer(5) 
invoke(_.reverse) // -> Container[S] = SContainer(ollah) 

그리고이 허용되지 않습니다 :

invoke(Symbol(_)) 

편집

대신 Container[T]Container[U]을 원하는, 그것은지면 간단 :

object Container { 
    implicit def stuffS(s: S): Container[S] = new SContainer(s) 
    implicit def stuffT[U <: T](u: U): Container[U] = new TContainer(u) 
} 
sealed trait Container[U] 
case class SContainer(s: S) extends Container[S] 
case class TContainer[U <: T](u: U) extends Container[U] 

def invoke[A <% Container[A]](f: String => A): Container[A] = f("hallo") 

invoke(_.size)  // Container[Int] 
invoke(_.reverse) // Container[String] 
invoke(Symbol(_)) // forbidden 
+0

원래 질문을 너무 단순화 한 것처럼 보입니다.하지만 내 질문을 제시하는 방식에 대한 솔루션이 완벽하고 유효합니다. – andri

+0

나는 당신이 무엇을 의미하는지 안다 :) 행운을 빈다! –

0

난 당신의 정의를 분리해야한다고 생각 컨테이너 자체에서 사용할 수있는 유형 정의에서 컨테이너.

먼저 S가 String이고 T가 더미 클래스라고 가정 해 봅시다.

sealed class AcceptableContent[X] private() 
object AcceptableContent { 
    implicit object SAcceptable extends AcceptableContent [S] 
    implicit def TAcceptable[U <: T] = new AcceptableContent[U] 
} 

이제 컨테이너 클래스는 다음과 같이 정의 할 수 있습니다 :

class Container[R : AcceptableContent](content: R) 
이제
class A 
class B extends A 

type T = A 
type S = String 

,의는 우리의 컨테이너에 대한 허용 내용으로 T의 S와 서브 클래스를 정의 할 typeclass 패턴을 사용하자

컨텍스트 바운드 : AcceptableContent은 원하는 범위의 암시 적 AcceptableContent [R]이있는 경우에만 R을 허용 할 수 있다고 말합니다. 지금 사실 는 :

scala> new Container("test") 
res0: Container[java.lang.String] = [email protected] 

scala> new Container(new A) 
res1: Container[A] = [email protected] 

scala> new Container(new B) 
res2: Container[B] = [email protected] 

scala> new Container(true) // Ok, Container accepts String, A, B but not Boolean 
<console>:12: error: could not find implicit value for evidence parameter of type AcceptableContent[Boolean] 

그래서 호출 지금이된다 : 모순이 여기에있다

def invoke[N : AcceptableContent](f: String => N) : Container[N] = new Container(f("test")) 
관련 문제