使用 flatMap(对于选项数据类型)调用映射,但类型在 scala 中不匹配



我正在进行"Scala中的函数式编程"练习,在第4章中,有一段关于Option类的代码,我认为我很难理解。

我被要求实现flatMap。我知道Map是指将A转换为B,然后将其封装在Option中。那么flatMap的目的到底是什么呢?如果我没有记错的话,在列表中实现的flatMap意味着采用一个函数,将a转换为B.A => List[B]的List。原则上,我想这也适用于这里。Option只是一个包含一个元素的列表,我将给它一个函数,该函数旨在获取一个a并将其封装在Option中。

我不知道如何使用Map实现flatMap。显而易见的实现方式很简单:

def flatMap(f: A => Option[B]): Option[B] = map(f) getOrElse None

为什么这种实施有效?f没有A=>B的类型签名,但它用这个签名调用map就可以了。显然,调用getOrElse(None(是它工作的原因,因为如果我去掉它,实现就会开始抱怨。但我不明白为什么scala解释器没有在这里抱怨。我们知道f返回一个Option[B]。返回的Option是否调用getOrElse,然后打开其值,以便具有正确的类型签名?如果是这样的话,有没有其他方法可以更明显地说明为什么它会起作用?

def flatMap[B](f: A => Option[B]): Option[B] = map((a)=> f(a).getOrElse(None)) // doesn't work

不幸的是,这本书并没有真正深入地介绍scala,所以我不确定这是语法(非常确定它的语法(还是我不理解的逻辑。

import scala.{Option => _, Some => _, Either => _, _} // hide std library `Option`, `Some` and `Either`, since we are writing our own in this chapter
sealed trait Option[+A] {
def map[B](f: A => B): Option[B] = this match {
case Some(a) => Some(f(a))
case None => None
}
def getOrElse[B>:A](default: => B): B = this match {
case None => default
case Some(b) => b
}
def flatMap[B](f: A => Option[B]): Option[B] = 
map(f) getOrElse(None)

def orElse[B>:A](ob: => Option[B]): Option[B] = ???
def filter(f: A => Boolean): Option[A] = ???
}
case class Some[+A](get: A) extends Option[A]
case object None extends Option[Nothing]
object Option {
def mean(xs: Seq[Double]): Option[Double] =
if (xs.isEmpty) None
else Some(xs.sum / xs.length)
def variance(xs: Seq[Double]): Option[Double] = ???
def map2[A,B,C](a: Option[A], b: Option[B])(f: (A, B) => C): Option[C] = ???
def sequence[A](a: List[Option[A]]): Option[List[A]] = ???
def traverse[A, B](a: List[A])(f: A => Option[B]): Option[List[B]] = ???
}

你对flatMap含义的直觉是完全正确的。我相信您对实现的困惑源于B是每个方法定义的类型参数,因此,当一个方法调用另一个方法时,它不必具有相同的

为了显示这一点,让我们简单地给这些方法的类型参数不同的名称:

def map[B](f: A => B): Option[B] = this match {
case Some(a) => Some(f(a))
case None => None
}
def getOrElse[C>:A](default: => C): C = this match {
case None => default
case Some(b) => b
}
def flatMap[D](f: A => Option[D]): Option[D] = {
map(f) getOrElse None
}

现在:

  • flatMap有一个类型参数D,它可以是任何东西
  • flatMap调用map时,它将Option[D]指定为map的类型参数B(!(的值。就map而言,它被传递了一个函数f到某种类型的B,这实际上是某种类型DOption[D](但map不在乎!(
  • flatMap调用getOrElse时——类似的事情发生了,这次getOrElse的类型参数C被分配了值Option[B]——同样,getOrElse只是"做它的事情",而不关心输出恰好是Option本身

这样,返回的值是:

  • None,如果原始输入是None(因为getOrElse将返回其传递的default(
  • 如果f返回None,则返回None(因为getOrElse将返回其获得的Some中的值,该值本身就是None(
  • 如果f的输入和结果均为Some,则为Some(v)

这正是flatMap应该做的。

最新更新