Преобразование последовательности операций карты в понимание

В разделе 23.5 «Программирование на Scala» я читал, что операции map, flatMap и filter всегда можно преобразовать в for-complation и наоборот.

Нам дана следующая эквивалентность:

def map[A, B](xs: List[A], f: A => B): List[B] =
  for (x <- xs) yield f(x)

У меня есть значение, рассчитанное на основе серии операций с картой:

val r = (1 to 100).map{ i => (1 to 100).map{i % _ == 0} }
                  .map{ _.foldLeft(false)(_^_) }
                  .map{ case true => "open"; case _ => "closed" }

Мне интересно, как это будет выглядеть для понимания. Как мне это перевести?

(Если это поможет, на словах это:

  • взять целые числа от 1 до 100
  • для каждого создайте список из 100 логических значений
  • сворачиваем каждый список с помощью оператора XOR обратно в логическое
  • вывести список из 100 строк "открытых" или "закрытых" в зависимости от логического

Я полагаю, что существует стандартный способ перевода операций с картой, и детали фактических функций в них не важны. Хотя я мог ошибаться.)


person Luigi Plinge    schedule 30.07.2011    source источник


Ответы (1)


Вы ищете именно такой перевод?

for (i <- 1 to 100;
     val x = (1 to 100).map(i % _ == 0);
     val y = x.foldLeft(false)(_^_);
     val z = y match { case true => "open"; case _ => "closed" })
  yield z

При желании map в определении x можно также перевести во «внутреннее» понимание.

Оглядываясь назад, можно сказать, что серия связанных вызовов map довольно тривиальна, поскольку вы могли бы эквивалентно вызвать map один раз с составными функциями:

 s.map(f).map(g).map(h) == s.map(f andThen g andThen h)

Я нахожу, что понимание будет больше, когда задействованы flatMap и filter. Учитывать

for (i <- 1 to 3;
     j <- 1 to 3 if (i + j) % 2 == 0;
     k <- 1 to 3) yield i ^ j ^ k

против

(1 to 3).flatMap { i =>
  (1 to 3).filter(j => (i + j) % 2 == 0).flatMap { j =>
    (1 to 3).map { k => i ^ j ^ k }
  }
}
person Kipton Barros    schedule 30.07.2011
comment
Это полезно, спасибо. Я могу избавиться от множества карт, собрав все вместе в разделе yield без промежуточных переменных, следовательно: val r = for (i <- 1 to 100) yield (1 to 100).map(i % _ == 0).foldLeft(false)(_^_) match { case true => "open"; case _ => "closed" }. (Я также пробовал andThen, но он немного сложнее.) - person Luigi Plinge; 30.07.2011