Поведение вариантов внутри для понимания является Scala
Два вопроса новичка.
Кажется, что for
понимание знает о Options
и может автоматически пропустить None
и развернуть Some
например,
val x = Map("a" -> List(1,2,3), "b" -> List(4,5,6), "c" -> List(7,8,9))
val r = for {map_key <- List("WRONG_KEY", "a", "b", "c")
map_value <- x get map_key } yield map_value
выходы:
r: List[List[Int]] = List(List(1, 2, 3), List(4, 5, 6), List(7, 8, 9))
Где сделать Options
идти? Может кто-нибудь, пожалуйста, пролить свет на то, как это работает? Можем ли мы всегда полагаться на это поведение?
Второе, почему это не компилируется?
val x = Map("a" -> List(1,2,3), "b" -> List(4,5,6), "c" -> List(7,8,9))
val r = for {map_key <- List("WRONG_KEY", "a", "b", "c")
map_value <- x get map_key
list_value <- map_value
} yield list_value
Это дает
Error:(57, 26) type mismatch;
found : List[Int]
required: Option[?]
list_value <- map_value
^
Глядя на тип первого примера, я не уверен, почему нам нужно иметь Option
Вот?
4 ответа
Может быть, эта небольшая разница, установка скобок и вызов flatten, проясняет:
val r = for {map_key <- List("WRONG_KEY", "a", "b", "c")
| } yield x get map_key
r: List[Option[List[Int]]] = List(None, Some(List(1, 2, 3)), Some(List(4, 5, 6)), Some(List(7, 8, 9)))
val r = (for {map_key <- List("WRONG_KEY", "a", "b", "c")
| } yield x get map_key).flatten
r: List[List[Int]] = List(List(1, 2, 3), List(4, 5, 6), List(7, 8, 9))
Это эквивалентно:
scala> List("WRONG_KEY", "a", "b", "c").map (x get _)
res81: List[Option[List[Int]]] = List(None, Some(List(1, 2, 3)), Some(List(4, 5, 6)), Some(List(7, 8, 9)))
scala> List("WRONG_KEY", "a", "b", "c").map (x get _).flatten
res82: List[List[Int]] = List(List(1, 2, 3), List(4, 5, 6), List(7, 8, 9))
Промежуточное значение (map_key) исчезло как _ во втором блоке.
Вы смешиваете две разные монады (List
а также Option
) внутри для заявления. Это иногда работает, как ожидалось, но не всегда. В любом случае вы можете самостоятельно преобразовывать параметры в списки:
for {
map_key <- List("WRONG_KEY", "a", "b", "c")
list_value <- x get map_key getOrElse Nil
} yield list_value
Я думаю, что разница заключается в том, что понимание разбирается в вызовах метода map() и flatMap внутри черты Seq.
Для краткости давайте определим некоторые переменные:
var keys = List("WRONG_KEY", a, b, c)
Ваш первый случай эквивалентен:
val r = keys.flatMap(x.get(_))
тогда как ваш второй случай эквивалентен:
val r= keys.flatMap(x.get(_).flatMap{ case y => y })
Я думаю, что проблема в том, что Option.flatMap() должен возвращать Option[], что хорошо в первом случае, но не согласуется во втором случае с тем, что передается x.get(). FlatMap, который является Список [Int].
Эти правила перевода для понимания более подробно объясняются в главе 7 "Программирование Scala" Wampler & Payne.
Для понимания преобразуются в вызовы в последовательность вызовов карты или flatMap. Смотрите здесь
Ваш for
цикл эквивалентен
List("WRONG_KEY", "a", "b", "c").flatMap(
map_key => x.get(map_key).flatMap(map_value => map_value)
)
flatMap
в Option
определяется как
@inline final def flatMap[B](f: A => Option[B]): Option[B]
Так что не разрешено проходить List
в качестве аргумента, как вы уведомлены компилятором.