帮助我理解这一点

时间:2011-08-19 08:13:47

标签: scala

我有以下(工作)代码

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

我给你这里的类型

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

将其更改为此for-comprehension会给我一个编译错误

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

请解释为什么我的理解错误。

3 个答案:

答案 0 :(得分:8)

您不能flatMap选项。看看它的类型签名:

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

因此,flatMap解压缩选项,但需要一个新的选项,因此您需要一个替代方案。您可以使用Map的方法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-expression不同。表达式

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)

答案 1 :(得分: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而不是Option的? Option已被flatMap淘汰,但从未发挥过作用。

您的代码或多或少等同于理解:

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

这引入了一些身份地图:map(sss => sss)map(s => s),它们解决了for-comprehension中的最后一个生成器始终为map的事实。

答案 2 :(得分:0)

重要的是要理解一个for comprehension会产生所输入的集合类型。那么为什么你的代码不起作用你想要返回一个元素。试试这个:

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

:/希望这会有所帮助