Коллекция Scala: абсолютно непредсказуемое поведение - PullRequest
2 голосов
/ 20 июля 2010

Были довольно разочарованы поведением коллекции Scala 2.8.Вот проблема: я создаю доску судоку.Я помечаю ячейки от A1 до I9 (буквы - это строки, а цифры - столбцы).Я хочу получить список единиц на доске, который состоит из 9 строк, ночных столбцов и ночных квадрантов.

Вот мой класс scala:

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 ()?

Кроме того, когда я наблюдаю вывод метода run, кажется, что коллекция, возвращаемая ключевым словом yieldслучайное переключение между вектором и списком:

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)))

Я полностью потерян здесь.

Ответы [ 3 ]

8 голосов
/ 20 июля 2010

Результат выходного значения для понимания определяется типом первого генератора, в вашем методе вы ограничиваете типы своих параметров до тех пор, пока не потеряете свои методы: +.

3 голосов
/ 21 июля 2010

Несмотря на действительно странное поведение, :+ не может быть тем оператором, который вам нужен.Поскольку вы не аннотировали возвращаемый тип unitList, я не знаю, что вы ожидали.Я предполагаю, что вы хотели вернуть либо Iterable[Square], либо Iterable[Iterable[Square]].Итак, давайте посмотрим, как вы можете их получить, и почему :+ неверно.

Прежде всего, u1, u2 и u3 - это все Iterable[Iterable[Square]], хотя точный подтип варьируется.Это должно быть легко понять: cross возвращает Iterable[Square], так что в результате cross для понимания получается Iterable[Iterable[Square]].

Далее, давайте рассмотрим :+.Этот метод добавляет элемент в коллекцию, поэтому, если u1 равно Iterable(a, b, c), где a, b и c равны Iterable[Square], то u1 :+ u2 равно Iterable(a, b, c, u2), и его тип становится Iterable[X], где X - это объединение Iterable[Square] (тип a, b и c) и Iterable[Iterable[Square]] (тип u2).Конечный результат - Iterable[Iterable[AnyRef]].

Поскольку типы u1, u2 и u3 по сути одинаковы, правильная операция по всей вероятности такова:

u1 ++ u2 ++ u3

Который вернет Iterable[Iterable[Square]].Теперь, если вы хотите удалить вложенность и вернуть Iterable[Square], вы можете сгладить это:

(u1 ++ u2 ++ u3).flatten

Одна из этих двух вещей, вероятно, то, что вы хотите.

Теперь, что касаетсяпереключение " random ", в этом нет ничего случайного.В каждом случае есть два для понимания, и фактическая реализация результирующей коллекции зависит от реализации оригинальной коллекции.Итак, давайте рассмотрим это:

  • u1: внешний тип происходит от Range, внутренний тип от String (первый параметр для пересечения)
  • u2: внешний тип происходит от String, внутренний тип от List (первый параметр для пересечения)
  • u3: внешний тип происходит от List, внутренний тип от String (первый параметр для пересечения)

Таким образом, можно легко вывести, что for-понимания более String (WrappedString, на самом деле) и Range приводят к Vector, в то время как for-понимания более List приводят к List.

2 голосов
/ 20 июля 2010

Ошибка компилятора возникает из-за того, что :+ является членом IndexedSeq (и, следовательно, List), но не Iterable.Если вы измените возвращаемое значение unitList с

u1 :+ u2 :+ u3

на

List(u1) :+ u2 :+ u3

, оно будет прекрасно скомпилировано.

...