2009-12-27 5 views
1

상위 유형 바인드가있는 유형 및 매개 변수화 된 유형을 사용하여 문제점이 발생했습니다. Scala 컴파일러는 DefaultEdge 유형을 찾고 있지만 Edge[Type]을 필요로한다고 알려줍니다. 내가 case DefaultEdge[Type] 같은 것을 사용했지만 구문 오류가 발생합니다.상위 유형 바인드가있는 케이스 클래스

여기가 나의 설정입니다. 나는 서로 다른 타입에 대응하는 두 개의 엣지 케이스 클래스를 가지고있다. 이러한 클래스는 그럼 난 방법 중 몇 가지를 정의 GraphLike라는 특성을 가지고있는 파라미터 화 된 형태의 V.

object EdgeKind extends Enumeration { 
    type EdgeKind = Value 
    val Default, Jump, True, False, DefaultCase, Case, Throw, Return = Value 
} 

sealed abstract class Edge[V <: VertexLike](val startVertex: V, val endVertex: V, val kind: EdgeKind.EdgeKind) 

case class DefaultEdge[V <: VertexLike](override val startVertex: V, override val endVertex: V) 
    extends Edge[V](startVertex, endVertex, EdgeKind.Default) 
case class JumpEdge[V <: VertexLike](//... 

가 포함되어 있습니다. 일부 GraphLike 특성의 방법과는 GraphLikeWithAdjacencyMatrix라고

trait GraphLike[V <: VertexLike] { 
    protected type E <: Edge[V] 
} 

또 다른 특성 구현 사이에서 : 유일한 흥미로운 부분이 하나 여야합니다. 모든 것을 함께 연결하면 다음과 같은 클래스를 갖게됩니다.

class CFG extends GraphLikeWithAdjacencyMatrix[BasicBlockVertex] { 
    def dotExport = { 
    def vertexToString(vertex: BasicBlockVertex) = "" 
    def edgeToString(edge: E) = edge match {//also tried Edge[BasicBlockVertex] here 
     case DefaultEdge => error("CFG may not contain default edges.") 
     case JumpEdge => "jump" 
     case TrueEdge => "true" 
     case FalseEdge => "false" 
     case DefaultCaseEdge => "default" 
     case CaseEdge => "case" 
     case ThrowEdge => "throw" 
     case ReturnEdge => "return" 
    } 
    new DOTExport(this, vertexToString, edgeToString) 
    } 
} 

여기에는 문제가 발생합니다. Edge [BasicBlockVertex]가 예상되며 DefaultEdge 만 제공한다고 들었습니다. DOTExport의 정의는 class DOTExport[V <: VertexLike](val graph: GraphLike[V], val vertexToString: V => String, val edgeToString: Edge[V] => String)

입니다. 제 질문은 이제 어떻게 가장자리 유형에 대한 사례 클래스를 사용하여 컴파일러를 행복하게 만들 수 있습니까? 내 멍청한 실수 야. 나는 가장자리 [가?] 필요하기 때문에 DefaultEdge(x,y) 대신 DefaultCase 등의 그러나 다음 DOTExport의 인스턴스가 실패 할 말을 한 번 그런데

으로 경기-코드가 작동하고 나는

감사합니다 CFG.E에게 전달합니다!

편집 : 사실 GraphLike에서 E = Edge[V]의 조합 DefaultEdge(_, _) 작품을 사용. 불행히도 이것은 시도와 오류의 결과 일뿐입니다. 나는 그것이 지금 왜 효과가 있는지 정말로 알고 싶다.

오류 메시지 : 여기

(fragment of test.scala):25: error: 
type mismatch; found : 
(Graph.this.E) => java.lang.String 
required: (this.Edge[?]) => String 
    new DOTExport(this, (vertex: V) => vertex.toString, edgeToString) 

내 문제를 설명 전체 컴파일 가능한 코드입니다. 다시, 제 문제는 라인 14입니다. 왜냐하면 type E <: Edge[V]type E = Edge[V]으로 바꿀 때 모든 것이 작동하기 때문에 나는 그 이유를 모릅니다.

object EdgeKind { 
    val Default = 0 
    val Jump = 1 
} 

abstract class Edge[V <: VertexLike](val startVertex: V, val endVertex: V, val kind: Int) 

case class DefaultEdge[V <: VertexLike](override val startVertex: V, override val endVertex: V) extends Edge[V](startVertex, endVertex, EdgeKind.Default) 
case class JumpEdge[V <: VertexLike](override val startVertex: V, override val endVertex: V) extends Edge[V](startVertex, endVertex, EdgeKind.Jump) 

trait VertexLike 

trait GraphLike[V <: VertexLike] { 
    protected type E <: Edge[V] // Everything works when E = Edge[V] 
} 

class DOTExport[V <: VertexLike](val graph: GraphLike[V], val vertexToString: V => String, val edgeToString: Edge[V] => String) 

class Graph[V <: VertexLike] extends GraphLike[V] { 
    def dotExport = { 
    def edgeToString(edge: E) = edge match { 
     case DefaultEdge(_, _) => "" 
     case JumpEdge(_, _) => "jump" 
    } 
    new DOTExport(this, (vertex: V) => vertex.toString, edgeToString) 
    } 
} 
+1

컴파일 가능한 코드를 제공하면 도움이 될 것입니다. 또한 실제로 발생하는 줄에서 정확한 줄과 위치의 표시를 포함하여 실제 오류 메시지를 제공하면 실제로는 도움이 될 것입니다. –

답변

3

정말 도움이 될만한 것이 누락되었습니다. 정확한 오류 메시지를 대신 설명해야합니다.

어쨌든 case DefaultEdge은 전달 된 객체와 객체 DefaultEdge 사이의 비교를 의미합니다. 후자는 클래스 DefaultEdge의 오브젝트 컴패니언이며, case class 문을 사용하여 자동 생성됩니다. 이러한 동반 객체 은 동등한 클래스에 속하지 않습니다.. 그것들은 자신의 클래스가 그들 자신에게 고유하다는 것을 의미하는 싱글 톤이며, 그렇지 않으면 그냥 AnyRef을 상속합니다.

즉, DefaultEdgeEdge이 아니므로 오류가 발생합니다. DefaultEdge(_, _)을 사용했을 때의 오류에 관해서는 너무 자세하지 않았습니다. 하나...그런 식으로 코드를 작성하셨습니까? 나는 대신 다음을 기대 :

new DOTExport(this, vertexToString _, edgeToString _) 

편집

좋아, 두 번째 오류 메시지는 이제 분명하다. E의 원래 선언은 하위 클래스Edge이지만, DOTExportEdge을 사용하고 String으로 변환하는 함수를 예상합니다. IntEdgeStringEdge :

protected type E >: Edge[V] 

Edge의 두 서브 클래스를 가지고 문제를 설명하기 위해 가정 해 봅시다 : 여기에 문제를 이해하려면 다음과 같은 정의도 작동합니다. 첫 번째 필드에는 number 필드가 있고 두 번째 필드에는 name 필드가 있습니다. 그래서, 우리는 다음과 같은 기능을 쓸 수있다 :

def intEdgeToString(ie: IntEdge) = ie.number.toString 
def stringEdgeToString(se: StringEdge) = se.name 

을 지금,이 var를 작성하고 그 중 하나를 저장할 수 : Edge의 서브 클래스입니다

var eTS: E => String = intEdgeToString _ 

E 때문에, 이것은 허용 될 것이다. 따라서 DOTExporteTS으로 전달합니다. 다음으로 DOTExportIntEdge이 아닌 StringEdge으로 공급됩니다. 후자에는 number 필드가 없으므로 실행하려고하면 실행시 예외가 발생하여 정적 타이핑의 모든 목적을 달성 할 수 없습니다.

스칼라가 원래 정의를 수락하지 않은 이런 종류의 문제를 방지하는 것입니다.

+0

'vertexToString'과'edgeToString'가 0보다 많은 파라미터를 사용하기 때문에 밑줄이'new DOTExport' 호출에서 필요하지 않다고 생각합니다. http://programming-scala.labs.oreilly.com/ch08.html : >'map' 연산은 함수를 인자로 기대하기 때문에'map (println _)'을 쓸 필요가 없습니다. 후행 밑줄은이 문맥에서'println'을 함수 값으로 바꾸는 것이 암시된다는 것입니다. –

+0

하지만 E> : Edge [V]는 "Edge [V]가 확장되는 모든 클래스 E"를 의미하지 않습니다? IntEdge가 Edge를 확장시킬거야, 안 그래? –

+0

아니요,'E> : Edge [V]'는 'Edge [V]'의 수퍼 클래스, 예를 들어'AnyRef'를 의미합니다. 그래서'AnyRef => String'의 함수를 전달할 수 있습니다.이 함수는'Edge'에서 작동하지만'IntEdge'를 전달할 수는 없습니다. 이것은 분산 (공분산, 반 차별) 및 유형 경계를 이해하는 데 실제로 문제이므로 해당 개념을 읽어야합니다. 재미를 위해서, 하나의 매개 변수 함수의 타입 시그니처는'Function [-T, + R]'입니다. 타입 시그니처가 당신에게 완벽 할 때 분산을 주로 이해하게 될 것입니다. –

2

첫째, 다니엘은 정확한 정보를 제공하는 것이 많은 도움이 될 것이라는 점을 확실히 알고 있습니다. 함수 값으로하지 사용될 때이 잘못된 일을 일치 DefaultEdge 1) 패턴) edgeToString(edge: E) = ...edgeToString 의미가 유형 CFG.E => String을 가지고 있기 때문에

def edgeToString(edge: Edge[BasicBlockVertex]) = edge match { 
    case DefaultEdge(_,_) => error("CFG may not contain default edges.") 
    case JumpEdge(_,_) => "jump" 
    case TrueEdge(_,_) => "true" 
    ... 

: 당신은 당신이 함께 노력 모두 일을 할 필요가 같이 그러나 보인다 Edge[V] => String이므로 new DOTExport으로 전달할 수 없습니다.

관련 문제