2011-08-19 49 views
3

我有以下的(工作)代碼幫我把這個理解力右

val superSuperSorts = superSorts.flatMap(relations.get(_)).flatMap(x=>x) 

而且我給你這裏的類型

val superSorts: Set[Sort] 
val relations: Map[Sort, Set[Sort]] 

它更改爲這個換的理解給了我一個編譯該讀數的誤差

val superSuperSorts = 
    for(
    ss <- superSorts; 
    sss <- relations.get(ss); //get Option[Set[Sort]] and flatten the option 
    s <- sss     //extract the elements from the Set 
) yield s 

error: type mismatch; 
found : scala.collection.immutable.Set[edu.uulm.scbayes.logic.Sort] 
required: Option[?] 
s <- sss 

請解釋爲什麼我的理解錯誤。

回答

8

您不能flatMap一個選項。看看它的類型簽名:

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

所以,flatMap解壓選項,但需要一個新的選項,所以你需要一個替代。您可以使用地圖選項的方法getOrElse或方法seq

val superSuperSorts = for { 
    s <- superSorts 
    ss <- relations.getOrElse(s, Set.empty) 
} yield s 

val superSuperSorts = for { 
    s <- superSorts 
    ss <- relations.get(s).seq 
    sss <- ss 
} yield sss 

的另一個問題是,你flatMap代碼不等於用你的表達。表達

for (x <- expr1; y <- expr2) yield expr3 

被翻譯成

expr1.flatMap(x => for (y <- expr2) yield expr3) 

,並在另一個步驟

expr1.flatMap(x => expr2.map(y => expr3)) 

但是你必須:

expr1.flatMap(x => expr2).flatMap(y => expr3) 
+0

我想我可以使用for-comprehension來壓扁Option。 – ziggystar

+0

它確實檢查了這個代碼:val m = Map(1 - >「a」,2 - >「b」)。 for(lx < - List(1,3); a <-m.get(lx))產生a。觀察返回類型! – AndreasScheinert

+0

我更新了我的答案。也許現在更清楚了。 – sschaef

0

重要的是要明白,一個用於理解會產生類型的收集fed。因此,爲什麼你的代碼不工作是你想返回一個單一的元素。試試這個:

val superSuperSorts = 
  for(
  ss <- superSorts; 
  sss <- relations.get(ss); //get Option[Set[Sort]] and flatten the option 
) yield sss 

:/希望這有助於

+0

所以這將返回一個'Set [Set [Sort]]'?但我希望它變平。 – ziggystar

+0

對我的回答誤導你的問題。關鍵點由Antoras解釋。由於您的Map操作返回單個選項,因此必須從中重新打包/構建結果集。 – AndreasScheinert

1

讓我舉一個例子來弄清楚問題出在哪裏。比方說,你有:

val superSorts = Set('x) 
val relations = Map('x -> Set('a, 'b)) 

此代碼:

val superSuperSorts = 
    for(
    ss <- superSorts; 
    sss <- relations.get(ss); //get Option[Set[Sort]] and flatten the option 
    s <- sss     //extract the elements from the Set 
) yield s 

翻譯爲:

superSorts.flatMap(
    ss => relations.get(ss).flatMap(
    sss => sss.map(
     s => s))) 

首先,請注意,最後一項是map,而不是一個flatMap。現在,讓我們考慮用以上數據進行迭代:

ss = 'x 
sss = Set('a, 'b) 
s = 'a, 'b 

現在讓我們在代碼中向後走。

// Set('a, 'b) => Set('a, 'b) 
sss.map(s => s) 

// Some(Set('a, 'b)) => Some('a, 'b)???? 
relations.get(ss).flatMap(...) 

看到問題在這裏? Option[Set[Sort]]如何平展?有沒有這樣的事情作爲Some('a, 'b)

那麼,爲什麼原始代碼工作?

val superSuperSorts = superSorts.flatMap(relations.get(_)).flatMap(x=>x) 

如果我們把它分解:

// Set('x) => Set(Set('a, 'b)) 
superSorts.flatMap(relations.get(_)) 

// Set(Set('a, 'b')) => Set('a, 'b) 
(...).flatMap(x=>x) 

就能查看所有的flatMap被應用在Set,不是OptionOptionflatMap淘汰,從未發揮過作用。

的更多或更少的等價物,理解您的代碼將是:

val superSuperSorts = for { 
    x <- (for { 
    ss <- superSorts 
    sss <- relations.get(ss) 
    } yield sss) 
    s <- x 
} yield s 

這引入了幾個身份地圖:map(sss => sss)map(s => s),該回避的事實得到,在一個最後的發電機理解總是一個map

+0

我遇到的問題是我沒有意識到鏈接和嵌套flatMaps之間存在差異。或者:我沒有注意到for-comprehension中的flatMaps被嵌套。我認爲我應該使用更多的理解來獲得這種感覺。謝謝你的解釋。 – ziggystar