2016-10-04 46 views
0

表達式的第一個是基本示例。第二個for-expr引入了一個我認爲會產生相同輸出的細微變化。但由於編譯錯誤而失敗。什麼原因以及如何解決?用於理解的選項生成器強制其他生成器成爲選項?

for { 
    n <- List(1,2) 
    c <- "ABC" 
} yield s"$c$n" 
//res0: List[String] = List(A1, B1, C1, A2, B2, C2) 

for { 
    opt <- List(None, Some(1), None, None, Some(2), None) 
    n <- opt 
    c <- "ABC" 
} yield s"$c$n" 
//Error:(14, 5) type mismatch; 
//found : scala.collection.immutable.IndexedSeq[String] 
//required: Option[?] 
// c <- "ABC" 
// ^
+0

在這種情況下是的,因爲第二個提取器就像一個'flatMap',所以你需要返回一個選項。 爲了清楚起見,您可以在第一種情況下通過隱式轉換提取「ABC」,以便事物成爲列表並編譯,在第二種情況下,「ABC」不會隱式轉換爲選項。 –

回答

1

要回答標題問題:是的,第一個生成器「爲整個表達式設置心情」。請注意,像上面那樣的表達式是脫鉤轉換爲調用flatMap s和最後map(加上護士的withFilter)。

在你的情況下,第一換表達脫糖入下式:

List(1, 2).flatMap(n => "ABC".map(c => s"$c$n")) 

這可以工作,因爲Predef(其在每Scala的程序隱式地導入)提供的一個的隱式轉換StringSeq[Char]

val implicitlyConverted: Seq[Char] = "ABC" 

因此,它按照計劃檢查運行。

現在讓我們來給看看在第二的表達式是如何

List(None, Some(1), None, None, Some(2), None).flatMap(opt => opt.flatMap(n => "ABC".map(c => s"$c$n"))) 

再次,我們有相同類型的錯誤如上,如果我們打破錶達成幾行,我們可能會看到這個問題好一點點:

List(None, Some(1), None, None, Some(2), None).flatMap { 
    opt => 
    opt.flatMap { 
     n => 
     "ABC".map { 
      c => 
      s"$c$n" 
     } 
    } 
} 

這爲我們提供了以下錯誤:

<console>:12: error: type mismatch; 
found : scala.collection.immutable.IndexedSeq[String] 
required: Option[?] 
         "ABC".map { 
           ^

第二個flatMap因此期望Option[_],而("ABC".map(...))中的map返回IndexedSeq[String]

所以,這是原因。我們如何解決這個問題?最簡單的解決方案可能涉及使用保護和Option內強行提取值,就像這樣:

for { 
    n <- List(None, Some(1), None, None, Some(2), None) 
    c <- "ABC" if n.isDefined 
} yield s"$c${n.get}" 

解決這個特定的問題更普遍的方式包括單子變壓器,因爲這個問題的根源在於單子做不寫;這個問題是非常廣泛和複雜的,也許this reply可能會給你一個更一般的答案。

+0

答案的學術質量高於預期。非常感謝你。 – Polymerase

+0

@聚合酶謝謝,我很高興我一直在幫助! – stefanobaghino

2

另一種方式來「修理」它是改變順序:

for { 
    opt <- List(None, Some(1), None, None, Some(2), None) 
    c <- "ABC" 
    n <- opt 
} yield s"$c$n" 
//> List[String] = List(A1, B1, C1, A2, B2, C2) 

它的工作原理,因爲Scala可以轉換OptionList,而不是相反的方向。

實際上它比簡單轉換複雜得多,涉及CanBuildFrom。通常單子不會構成任何東西,但在Scala中有一些通過使用CanBuildFrom來完成。