이 구조로 인해 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)
Some을 List로 전환하면 잘 컴파일됩니다.
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
on a List
가 다른 것을 반환 하기 때문에 List
for comprehension의 결과는 물론 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
있습니다.
답변
기억하기 쉬운 팁 은 이해 를 위해 첫 번째 생성기의 컬렉션 유형 인 Option [Int]를 반환하려고합니다. 따라서 Some (1)으로 시작 하면 Option [T]의 결과를 예상해야합니다.
목록 유형 의 결과를 원하면 목록 생성기로 시작해야합니다.
왜이 제한이 있고 항상 일종의 시퀀스를 원할 것이라고 가정하지 않습니까? 돌아 오는 것이 합리적 일 수 있습니다 Option
. 다음 함수를 사용하여 Option[Int]
를 얻기 위해 무언가와 결합하려는를 가질 수 있습니다 Option[List[Int]]
. (i:Int) => if (i > 0) List.range(0, i) else None
; 그런 다음 이것을 작성하고 “말이 안되는”경우 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
. 따라서 Option과 List를 결합 할 수 없습니다. 다른 것들의 예를 들어 M
, 이 특성의 하위 클래스를 보십시오 .
왜 결합 않은 List[T]
으로 (T) => Option[T]
당신이 목록 시작 때 비록 사용할 수 있습니까? 이 경우 라이브러리는 더 일반적인 유형을 사용합니다. 따라서 List와 Traversable을 결합 할 수 있으며 Option에서 Traversable 로의 암시 적 변환이 있습니다.
결론은 이것입니다. 표현식이 반환 할 유형을 생각하고 해당 유형을 첫 번째 생성자로 시작합니다. 필요한 경우 해당 유형으로 포장하십시오.
답변
Option이 Iterable이 아닌 것과 관련이있을 수 있습니다. 암시 Option.option2Iterable
적은 컴파일러가 두 번째가 Iterable 일 것으로 예상하는 경우를 처리합니다. 루프 변수의 유형에 따라 컴파일러 마법이 다를 것으로 예상합니다.
답변
나는 항상 이것이 도움이된다는 것을 알았다.
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)