问题是你要将List[Option[T]]
平面地映射到List[T]
:
val l = List(Some("Hello"), None, Some("World"))
得到:
List(Hello, World)
但没有很好的解决方案:
l flatMap( o => o)
l flatMap identity[Option[String]]
l flatMap ( x => Option.option2Iterable(identity(x)))
for(x <- l; y <- x) yield y
由于从Option[T]
到Iterable[T]
的所需类型转换,使用身份功能的明显解决方案无效:
l flatMap identity
<console>:6: error: type mismatch;
found : A
required: Iterable[?]
l flatMap identity
有解决这个问题的方法吗?
部分问题是,如果需要隐式类型转换,为什么类型推断器的工作方式不同?
(讨论this question about the identity function时出现了这个问题。)
答案 0 :(得分:2)
让Option
扩展Iterable
特征;我想知道他们为什么不首先这样做......
请注意,该示例在带有类型提示的scala 2.8 中不起作用:
scala> val l = List(Some("Hello"), None, Some("World"))
l: List[Option[java.lang.String]] = List(Some(Hello), None, Some(World))
scala> l.flatMap(identity) : List[String]
<console>:6: error: type mismatch;
found : A
required: Traversable[?]
l.flatMap(identity) : List[String]
答案 1 :(得分:2)
隐含没有问题。如果它是列表列表,您将无法将identity
传递给map
或flatMap
。我们讨论map
而不是flatMap
,因为它更简单,所以我可以更好地解释我的想法。
identity
的类型为(A) => A
。 map
(A) => B
的类型,其中A
已知,因为它是对象的类型参数(即在List[String]
中,它是String
})。 identity
的{{1}}和A
的{{1}}都不知道。
现在,如果我们使用map
类型的左侧来推断B
的左侧,那么我们可以使用map
的右侧来推断右侧identity
。看一个周期? identity
的类型为map
的类型再次为map
的类型。我很确定类型推理器可以避免循环,否则它可能会陷入无限循环。
事实上,人们可以查看Odersky等人的Programming in Scala页面355中类型推理器的详细信息。在方法应用程序identity
中,它执行以下步骤:
map
(在我们的例子中是m(arg)
)是否具有已知类型(不,我们不知道m
)。map
(我们案例中为B
)是否具有已知类型(不,我们不知道arg
)。所以,你必须提供一种类型。例如:
identity
在Scala 2.8上,类型推理器有点聪明,并且可以在不明确传递类型的情况下处理第二个命令。