2011-08-19 64 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