Вопрос

Почему эта конструкция вызывает ошибку несоответствия типа в Scala?

for (first <- Some(1); second <- List(1,2,3)) yield (first,second)

<console>:6: error: type mismatch;
 found   : List[(Int, Int)]
 required: Option[?]
       for (first <- Some(1); second <- List(1,2,3)) yield (first,second)

Если я переключу кое -что со списком, он хорошо составляет:

for (first <- List(1,2,3); second <- Some(1)) yield (first,second)
res41: List[(Int, Int)] = List((1,1), (2,1), (3,1))

Это также работает нормально:

for (first <- Some(1); second <- Some(2)) yield (first,second)
Это было полезно?

Решение

Для понимания преобразуется в вызовы в map или же flatMap метод Например, это:

for(x <- List(1) ; y <- List(1,2,3)) yield (x,y)

становится этим:

List(1).flatMap(x => List(1,2,3).map(y => (x,y)))

Следовательно, первое значение цикла (в данном случае, List(1)) получит flatMap метод вызов. С flatMap на List Возвращает другого List, результат для понимания, конечно, будет List. Анкет (Это было новым для меня: для понимания не всегда приводит к потокам, даже не обязательно в Seqс.)

Теперь посмотрите, как flatMap объявлен в Option:

def flatMap [B] (f: (A) ⇒ Option[B]) : Option[B]

Имейте это в виду. Посмотрим, как ошибочно понимать Some(1)) преобразуется в последовательность вызовов карты:

Some(1).flatMap(x => List(1,2,3).map(y => (x, y)))

Теперь легко увидеть, что параметр flatMap звонок - это то, что возвращает List, но не Option, как требуется.

Чтобы исправить эту вещь, вы можете сделать следующее:

for(x <- Some(1).toSeq ; y <- List(1,2,3)) yield (x, y)

Это хорошо компилирует. Стоит отметить, что Option не подтип Seq, как часто предполагается.

Другие советы

Легкий совет, чтобы помнить, для понимания Попробую вернуть тип коллекции первого генератора, опция [int] в этом случае. Итак, если вы начнете с Некоторые (1) Вы должны ожидать результата варианта [t].

Если вам нужен результат Список Введите, вы должны начать с генератора списков.

Почему это ограничение и не предполагать, что вы всегда захотите какую -то последовательность? У вас может быть ситуация, когда имеет смысл вернуться Option. Анкет Может быть Option[Int] что вы хотите объединить с чем -то, чтобы получить Option[List[Int]], скажем, со следующей функцией: (i:Int) => if (i > 0) List.range(0, i) else None; Затем вы можете написать это и не получить, когда что -то не имеет смысла »:

val f = (i:Int) => if (i > 0) Some(List.range(0, i)) else None
for (i <- Some(5); j <- f(i)) yield j
// returns: Option[List[Int]] = Some(List(0, 1, 2, 3, 4))
for (i <- None; j <- f(i)) yield j
// returns: Option[List[Int]] = None
for (i <- Some(-3); j <- f(i)) yield j
// returns:  Option[List[Int]] = None

Как для понимания расширяются в общем случае, на самом деле являются довольно общим механизмом объединения объекта типа M[T] с функцией (T) => M[U] Чтобы получить объект типа M[U]. Анкет В вашем примере M может быть опцией или списком. В целом это должен быть тот же тип M. Анкет Так что вы не можете объединить опцию с списком. Для примеров других вещей, которые могут быть M, смотреть на подклассы этой черты.

Почему объединилось List[T] с (T) => Option[T] Работайте, хотя, когда вы начали со списка? В этом случае библиотека использует более общий тип, где это имеет смысл. Таким образом, вы можете объединить список с Traversable, и существует неявное преобразование из опции в Traverable.

Суть в следующем: подумайте о том, какой тип вы хотите, чтобы выражение вернулось, и начинать с этого типа в качестве первого генератора. Оберните его в этот тип, если это необходимо.

Вероятно, это как -то связано с тем, что вариант не является итерационным. Неявный Option.option2Iterable Буду справиться с случаем, когда компилятор ожидает второго, чтобы стать итерабильным. Я ожидаю, что магия компилятора отличается в зависимости от типа переменной петли.

Я всегда находил это полезным:

scala> val foo: Option[Seq[Int]] = Some(Seq(1, 2, 3, 4, 5))
foo: Option[Seq[Int]] = Some(List(1, 2, 3, 4, 5))

scala> foo.flatten
<console>:13: error: Cannot prove that Seq[Int] <:< Option[B].
   foo.flatten
       ^

scala> val bar: Seq[Seq[Int]] = Seq(Seq(1, 2, 3, 4, 5))
bar: Seq[Seq[Int]] = List(List(1, 2, 3, 4, 5))

scala> bar.flatten
res1: Seq[Int] = List(1, 2, 3, 4, 5)

scala> foo.toSeq.flatten
res2: Seq[Int] = List(1, 2, 3, 4, 5)
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top