Scala 为什么可以';我不试试平面图吗?
给定 为什么我不能将方法调用导致的尝试平面化?i、 eScala 为什么可以';我不试试平面图吗?,scala,Scala,给定 为什么我不能将方法调用导致的尝试平面化?i、 e val strings = Set("Hi", "there", "friend") def numberOfCharsDiv2(s: String) = scala.util.Try { if (s.length % 2 == 0) s.length / 2 else throw new RuntimeException("grr") } 不允许在尝试时使用flatMap的理由是什么?问题在于,在您的示例中,您并没有在尝试时使用
val strings = Set("Hi", "there", "friend")
def numberOfCharsDiv2(s: String) = scala.util.Try {
if (s.length % 2 == 0) s.length / 2 else throw new RuntimeException("grr")
}
不允许在尝试时使用flatMap的理由是什么?问题在于,在您的示例中,您并没有在尝试时使用flatMap。你正在做的平面图设置过度 集合上的平面映射采用集合[a],函数从a到集合[B]。正如Kigyo在下面的评论中指出的,这并不是Scala中设置的flatmap的实际类型签名,但flatmap的一般形式是:
M[A]=>(A=>M[B])=>M[B]
也就是说,它采用某种更高种类的类型,以及一个对该更高种类类型中的类型元素进行操作的函数,它将返回具有映射元素的相同更高种类类型
在您的例子中,这意味着对于集合的每个元素,flatmap都需要调用一个接受字符串的函数,并返回一个类型为B的集合,该集合可以是字符串(也可以是其他任何类型)
你的职能
def numberOfCharsDiv2(s: String) = if (s.length % 2 == 0)
Some(s.length / 2) else None
strings.flatMap(numberOfCharsDiv2) # => Set(1, 3)
正确地获取字符串,但错误地返回Try,而不是flatmap所需的另一个集
如果您使用“map”,代码将起作用,因为它允许您采用某种结构——在本例中为Set,并在每个元素上运行函数,将其从a转换为B,而函数的返回类型不符合封闭结构,即返回一个Set
strings.map(numberOfCharsDiv2)
res2:scala.collection.immutable.Set[scala.util.Try[Int]=Set(成功(1)、失败(java.lang.RuntimeException:grr)、成功(3))
让我们看看flatMap
的签名
numberOfCharsDiv2(s: String)
您的numberOfCharsDiv2
被视为String=>Try[Int]
Try
不是GenTraversableOnce
的子类,因此会出现错误。仅因为在集合
上使用flatMap
,就不需要提供集合的函数。该函数基本上必须返回任何类型的集合
那么为什么它与选项
一起工作呢选项
也不是GenTraversableOnce
的子类,但在选项
伴生对象中存在一个隐式转换,将其转换为列表
def flatMap[B](f: (A) => GenTraversableOnce[B]): Set[B]
还有一个问题。为什么不同时对Try
进行隐式转换呢?因为你可能得不到你想要的
flatMap
可以看作是一个map
,后跟一个flatten
假设您有一个列表[选项[Int]]
像列表(一些(1),没有,一些(2))
。然后,plant
将为您提供类型为List[Int]
的列表(1,2)
现在看一个带有Try
的示例<代码>列表(成功(1)、失败(异常)、成功(2))
类型为List[Try[Int]]
现在,扁平化如何应对失败
- 它是否应该像
那样消失?那么为什么不直接使用None
李>选项
- 是否应将其包括在结果中?然后是
。这里的问题是类型是列表(1,异常,2)
,因为您必须为List[Any]
和Int
找到一个通用的超类。你输了Throwable
这就是为什么没有隐式转换的原因。当然,如果您接受上述后果,您可以自己定义一个单子。它是Scala 2.11中的单子:
implicit def option2Iterable[A](xo: Option[A]): Iterable[A] = xo.toList
Kigyo很好地解释了为什么Scala没有隐式地做到这一点。简单地说,Scala不希望自动丢弃在一次尝试中保留的异常 Scala确实提供了一种简单的方法来显式地将Try转换为选项。以下是如何在平面图中使用Try:
scala> import scala.util._
import scala.util._
scala> val x: Try[String] = Success[String]("abc")
x: scala.util.Try[String] = Success(abc)
scala> val y: Try[String] = Failure[String](new Exception("oops"))
y: scala.util.Try[String] = Failure(java.lang.Exception: oops)
scala> val z = Try(x)
z: scala.util.Try[scala.util.Try[String]] = Success(Success(abc))
scala> val t = Try(y)
t: scala.util.Try[scala.util.Try[String]] = Success(Failure(java.lang.Exception: oops))
scala> z.flatten
res2: scala.util.Try[String] = Success(abc)
scala> t.flatten
res3: scala.util.Try[String] =
Failure(java.lang.UnsupportedOperationException: oops)
使用
选项
仅当存在隐式转换选项[A]=>Iterable[A]
时才有效。我想问一下这种转换背后的原理是什么,这样我们就可以把选项想象成一个最大为1的列表。超级方便,不是吗?我一直使用选项[A]=>Iterable[A]
隐式转换。我认为将选项视为0对1容器非常有用。flatMap
overSet[a]
需要一个来自a=>gentraversableone[B]
的函数。它不需要是一个集合[B]
。是的,我意识到这是一个具体的例子,我试图更多地讨论flatmap的一般情况,或者haskell中的bind,其结构是:(M[A])(A=>M[B]):M[B]。不幸的是,这回答了一个被误解的问题。回答得不错,特别是关于类型的部分,None
不包含任何值,可以轻松安全地删除它们,故障
相反,它包含一个有意义的值,因此不能(也不应该)删除,但保留它们意味着,如果存在转换,您最终将失去Any
的类型信息和安全列表,我想这是一个非常有力的论点。我理解你的答案,但我认为这不是代表std库的正确设计。数据类型是Try[A]
,因此我只关心A
s。我应该能够消除Try
,丢弃Failure
值-就像选项
语义一样。是的,Try
只有一个通用参数。但这仅仅是因为故障
的类型已设置为可丢弃
,不需要进一步的规范。当您也关心异常时,可以使用Try
。如果您不这样做:从一开始就使用选项
,或者在上使用选项
方法尝试
。对于您的情况:strings.flatMap(numberOfCharsDiv2(u).toOption)
+1,但可以说Try
在概念上是或的一种专门化。其中,或
仅处理正确的值
implicit def option2Iterable[A](xo: Option[A]): Iterable[A] = xo.toList
scala> import scala.util._
import scala.util._
scala> val x: Try[String] = Success[String]("abc")
x: scala.util.Try[String] = Success(abc)
scala> val y: Try[String] = Failure[String](new Exception("oops"))
y: scala.util.Try[String] = Failure(java.lang.Exception: oops)
scala> val z = Try(x)
z: scala.util.Try[scala.util.Try[String]] = Success(Success(abc))
scala> val t = Try(y)
t: scala.util.Try[scala.util.Try[String]] = Success(Failure(java.lang.Exception: oops))
scala> z.flatten
res2: scala.util.Try[String] = Success(abc)
scala> t.flatten
res3: scala.util.Try[String] =
Failure(java.lang.UnsupportedOperationException: oops)
strings.flatMap(numberOfCharsDiv2(_).toOption)