2010-07-20 2 views
2

Scala 2.8 컬렉션 동작에 상당히 좌절감을 느껴야합니다. 문제는 다음과 같습니다. 저는 스도쿠 보드를 만들고 있습니다. 나는 A1에서 I9까지의 셀에 라벨을 붙이고있다. (글자는 행이되고 숫자는 열이된다.) 나는 보드에 9 열, 야간 기둥 및 밤 사분면 단위의 목록을 가져오고 싶습니다.스칼라 컬렉션 : 완전히 예측할 수없는 동작

class Square(val row:Char, val column:Int) extends Pair[Char, Int](row, column) { 
    override def toString() = "" + row + column 
} 

object Board { 
    private val rows = "ABCDEFGHI" 
    private val cols = 1 to 9 
    private lazy val units = unitList(rows, cols) 
    private def cross(rows:Iterable[Char], columns:Iterable[Int]):Iterable[Square] = { 
     for (row <- rows; col <- columns) 
      yield new Square(row, col) 
    } 

    private def unitList(rows:Iterable[Char], cols:Iterable[Int]) = { 
     val u1 = (for (col <- cols) yield cross(rows, List(col))) 
     val u2 = (for (row <- rows) yield cross(List(row), cols)) 
     val u3 = (for (cols <- List("ABC", "DEF", "GHI"); rows <- List(1 to 3, 4 to 6, 7 to 9)) yield cross(cols, rows)) 

     u1 :+ u2 :+ u3 // won't compile, reason: :+ is not a member of Iterable[Iterable[sudoku.Square]] 
    } 

    def run() { 
     val u1 = (for (col <- cols) yield cross(rows, List(col))) 
     val u2 = (for (row <- rows) yield cross(List(row), cols)) 
     val u3 = (for (cols <- List("ABC", "DEF", "GHI"); rows <- List(1 to 3, 4 to 6, 7 to 9)) yield cross(cols, rows)) 
     println(u1) 
     println(u2) 
     println(u3) 
     val u4 = u1 :+ u2 :+ u3 // compiles 
     println(u1 :+ u2 :+ u3) // compiles and output correctly 
    } 
} 

코드의 주석을 참조하십시오

여기 내 스칼라 클래스입니다. 특히, 같은 코드가 unitList에서 컴파일되지 않고 run()에서 컴파일되고 제대로 실행되는 이유는 무엇입니까?

Vector(Vector(A1, B1, C1, D1, E1, F1, G1, H1, I1), Vector(A2, B2, C2, D2, E2, F2, G2, H2, I2), Vector(A3, B3, C3, D3, E3, F3, G3, H3, I3), Vector(A4, B4, C4, D4, E4, F4, G4, H4, I4), Vector(A5, B5, C5, D5, E5, F5, G5, H5, I5), Vector(A6, B6, C6, D6, E6, F6, G6, H6, I6), Vector(A7, B7, C7, D7, E7, F7, G7, H7, I7), Vector(A8, B8, C8, D8, E8, F8, G8, H8, I8), Vector(A9, B9, C9, D9, E9, F9, G9, H9, I9)) 

Vector(List(A1, A2, A3, A4, A5, A6, A7, A8, A9), List(B1, B2, B3, B4, B5, B6, B7, B8, B9), List(C1, C2, C3, C4, C5, C6, C7, C8, C9), List(D1, D2, D3, D4, D5, D6, D7, D8, D9), List(E1, E2, E3, E4, E5, E6, E7, E8, E9), List(F1, F2, F3, F4, F5, F6, F7, F8, F9), List(G1, G2, G3, G4, G5, G6, G7, G8, G9), List(H1, H2, H3, H4, H5, H6, H7, H8, H9), List(I1, I2, I3, I4, I5, I6, I7, I8, I9)) 

List(Vector(A1, A2, A3, B1, B2, B3, C1, C2, C3), Vector(A4, A5, A6, B4, B5, B6, C4, C5, C6), Vector(A7, A8, A9, B7, B8, B9, C7, C8, C9), Vector(D1, D2, D3, E1, E2, E3, F1, F2, F3), Vector(D4, D5, D6, E4, E5, E6, F4, F5, F6), Vector(D7, D8, D9, E7, E8, E9, F7, F8, F9), Vector(G1, G2, G3, H1, H2, H3, I1, I2, I3), Vector(G4, G5, G6, H4, H5, H6, I4, I5, I6), Vector(G7, G8, G9, H7, H8, H9, I7, I8, I9)) 

Vector(Vector(A1, B1, C1, D1, E1, F1, G1, H1, I1), Vector(A2, B2, C2, D2, E2, F2, G2, H2, I2), Vector(A3, B3, C3, D3, E3, F3, G3, H3, I3), Vector(A4, B4, C4, D4, E4, F4, G4, H4, I4), Vector(A5, B5, C5, D5, E5, F5, G5, H5, I5), Vector(A6, B6, C6, D6, E6, F6, G6, H6, I6), Vector(A7, B7, C7, D7, E7, F7, G7, H7, I7), Vector(A8, B8, C8, D8, E8, F8, G8, H8, I8), Vector(A9, B9, C9, D9, E9, F9, G9, H9, I9), Vector(List(A1, A2, A3, A4, A5, A6, A7, A8, A9), List(B1, B2, B3, B4, B5, B6, B7, B8, B9), List(C1, C2, C3, C4, C5, C6, C7, C8, C9), List(D1, D2, D3, D4, D5, D6, D7, D8, D9), List(E1, E2, E3, E4, E5, E6, E7, E8, E9), List(F1, F2, F3, F4, F5, F6, F7, F8, F9), List(G1, G2, G3, G4, G5, G6, G7, G8, G9), List(H1, H2, H3, H4, H5, H6, H7, H8, H9), List(I1, I2, I3, I4, I5, I6, I7, I8, I9)), List(Vector(A1, A2, A3, B1, B2, B3, C1, C2, C3), Vector(A4, A5, A6, B4, B5, B6, C4, C5, C6), Vector(A7, A8, A9, B7, B8, B9, C7, C8, C9), Vector(D1, D2, D3, E1, E2, E3, F1, F2, F3), Vector(D4, D5, D6, E4, E5, E6, F4, F5, F6), Vector(D7, D8, D9, E7, E8, E9, F7, F8, F9), Vector(G1, G2, G3, H1, H2, H3, I1, I2, I3), Vector(G4, G5, G6, H4, H5, H6, I4, I5, I6), Vector(G7, G8, G9, H7, H8, H9, I7, I8, I9))) 

나는 완전히 여기 손실에 있어요 : 나는 run 메소드의 출력을 관찰 할 때

또한, 그것은 항복 키워드에 의해 반환 된 컬렉션 무작위 벡터 및 목록 사이를 전환 할 것 같다.

답변

3

정말 이상한 행동에도 불구하고 :+은 원하는 운영자가 될 수 없습니다. 반환 유형을 unitList으로 주석 처리하지 않았으므로 예상 한 내용을 알 수 없습니다. Iterable[Square] 또는 Iterable[Iterable[Square]] 중 하나를 반환한다고 가정합니다. 자, 어떻게 얻을 수 있는지 보자. 왜 :+이 올바르지 않은가?

우선, 정확한 하위 유형은 다양하지만 u1, u2u3은 모두 Iterable[Iterable[Square]]입니다. 이것은 이해하기 쉬워야합니다. crossIterable[Square]을 반환하므로 이해를위한 의 결과는 Iterable[Iterable[Square]]입니다.

다음으로 :+을 고려해 보겠습니다. 이러한 방법은 컬렉션에 요소를 추가하고, 따라서 u1은 A, B 및 C Iterable[Square]있다 Iterable(a, b, c)이면 다음 u1 :+ u2Iterable(a, b, c, u2)이고 그 종류 XIterable[Square] 통일 (A, B의 형태 인 Iterable[X]을진다 및 c) 및 Iterable[Iterable[Square]] (유형은 u2 임). 최종 결과는 Iterable[Iterable[AnyRef]]입니다.

u1 ++ u2 ++ u3 

어느 Iterable[Iterable[Square]]를 반환 : u1, u2u3 유형 이후

본질적으로 동일하며, 모든 동반 할 가능성 올바른 동작이있다. 당신이 중첩을 제거하고 Iterable[Square]을 반환 할 경우 지금, 당신은이를 평평하게 할 수 이러한 두 가지의

(u1 ++ u2 ++ u3).flatten 

하나는 당신이 원하는 아마.

이제 "임의 번호"전환과 관련하여 아무 것도 없습니다. 각각의 경우에 두 가지 이해력이 있으며 결과 컬렉션의 실제 구현은 원본 컬렉션의 구현에 따라 다릅니다. 그래서, 현실을 살펴 보자 :

  • U1을 : 외부 유형 Range에서, 내부 유형 String에서 (첫 번째 매개 변수 건너) 파생
  • U2 : 외부 유형은 String에서, 내부 유형 List (첫 번째 매개 변수에서 건너 유래)
  • U3은 : List에서 내측 유형
  • 그래서

가 쉽게 도출 될 수있다) 교차 String (최초의 파라미터로부터 도출 외측 타입 유도한다 해당 피 COMPR String (실제로는 WrappedString) 이상이고 Range 인 결과는 Vector이고, 보완은 List 인 결과는 List이됩니다.

+0

자세한 설명을 주셔서 감사합니다. 나는 더 어제 코드를 쳐다 보았다. 그리고 그것은 모두 의미가 있기 시작했다. – EnToutCas

8

for the comprehension의 결과는 첫 번째 생성기의 형식에서 파생됩니다. 이제는 메서드에서 매개 변수의 형식을 제한합니다. :+IndexedSeq (따라서 List)의 부재가 아니라 Iterable의이므로

//The type of 1 to 9 is show below 
scala> 1 to 9 
res0: scala.collection.immutable.Range.Inclusive with scala.collection.immutable.Range.ByOne = Range(1, 2, 3, 4, 5, 6, 7, 8, 9) 


//If you cast it to Iterable[Int] it doens't have the :+ method 
scala> (res0:Iterable[Int]) :+ 1 
<console>:7: error: value :+ is not a member of Iterable[Int] 
     (res0:Iterable[Int]) :+ 1 
    ^

//But if you don't, you have it 
scala> res0 :+ 1     
res6: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 1) 

//And to prove that for comprehensions yield derives the type of the first generator: 

scala> for(a <- res0) yield a 
res7: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3, 4, 5, 6, 7, 8, 9) 

scala> for(a <- (res0:Iterable[Int])) yield a 
res8: Iterable[Int] = Vector(1, 2, 3, 4, 5, 6, 7, 8, 9) 
+0

감사합니다. 지금은 많은 의미가 있습니다. – EnToutCas

2

컴파일러 에러가 발생한다. 당신이

List(u1) :+ u2 :+ u3 

u1 :+ u2 :+ u3 

에서 unitList의 반환 값을 변경하는 경우는 잘 컴파일합니다.

+0

하지만 run() 메서드 내의 동일한 코드가 왜 컴파일되어 제대로 실행되는지에 대한 질문에는 대답하지 않았습니다. – EnToutCas

+0

이제 마음이 생기고, 지금은 의미가 있습니다. – EnToutCas

관련 문제