Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Scala中可遍历一次、未来和选项以便于理解_Scala_Monads_Future - Fatal编程技术网

在Scala中可遍历一次、未来和选项以便于理解

在Scala中可遍历一次、未来和选项以便于理解,scala,monads,future,Scala,Monads,Future,我有一个代表DB记录的字符串ID列表。我想异步地从DB加载它们,然后异步地将每条记录上载到远程服务器,然后在所有上载完成后,记录上载的记录的ID 因为我使用的是Scala 2.9.2,所以我使用的是Twitter的core util Future实现,但就一元转换而言,它应该与2.10 futures完全相同 一般的概念是: def fetch(id: String): Future[Option[Record]] def upload(record: Record): Future[Strin

我有一个代表DB记录的字符串ID列表。我想异步地从DB加载它们,然后异步地将每条记录上载到远程服务器,然后在所有上载完成后,记录上载的记录的ID

因为我使用的是Scala 2.9.2,所以我使用的是Twitter的core util Future实现,但就一元转换而言,它应该与2.10 futures完全相同

一般的概念是:

def fetch(id: String): Future[Option[Record]]
def upload(record: Record): Future[String]
def notifyUploaded(ids: Seq[String]): Unit

val ids: Seq[String] = ....
我试图通过一个简单的方法来理解这一点,但fetch返回一个Future of选项这一事实使它变得模糊,代码无法编译:

for {
  id <- ids
  maybeRecord <- fetch(id)
  record <- maybeRecord
  uploadedId <- upload(record)
} yield uploadedId
用于{

id考虑
flatMap
(或bind)函数的签名:

trait Monad[M[_]] {
  def flatMap[A](a : M[A], f : A => M[B]) : M[B]
  ....
在你的例子中,你试图在一个
选项上使用
flatMap
,给它一个
f
,它会生成一个
未来
。但是在上面的签名中,
f
应该在调用它的同一个单子中生成一些东西

Scala在这方面不一定非常有用,因为它非常擅长转换东西(例如,转换为
Seq
s),这样您就会得到这样一种印象,即您可以将任意
flatMap
调用链接在一起,而不必考虑容器


你可能想要的是一个“Monad transformer”,它能让你合成Monad。Debasish Ghosh有一篇关于使用Scalaz Monad transformers的帖子。

你不能将所有不同的类型混合在一起理解,我发现你可以混合Seq和Option,结果可能是Seq,也可能是Option,这取决于第一个是什么不可能混合使用Future和Seq或Option。如果你想使用它们进行理解,你必须将它们串联起来。在这种情况下,使用map/flatMap可能会更好。我以两种方式实现了你的问题,并在一些中间结果中添加了类型,这样你就可以看到在使用所有不同类型时产生的混乱

object TestClass {

  import scala.concurrent.Future
  import scala.concurrent.ExecutionContext.Implicits.global
  import scala.concurrent._
  import scala.concurrent.duration._

  case class Record(id: String)


  def fetch(id: String): Future[Option[Record]] = Future {
    Thread.sleep(1000);
    Some(Record(id))
  }

  def upload(record: Record): Future[String] = Future {
    Thread.sleep(3000);
    record.id + "_uploaded"
  }

  def notifyUploaded(ids: Seq[String]): Unit = println("notified" + ids)

  val ids: Seq[String] = Seq("a", "b", "c")

  def main(args: Array[String]): Unit = {
    forComprehensionImpl()
    mapAndFlatMapImpl()
  }

  def forComprehensionImpl() = {
    val result: Seq[Future[Option[Future[String]]]] = for {
      id <- ids
    } yield {
      for {
        maybeRecord <- fetch(id)
      } yield {
        for {
          record <- maybeRecord
        } yield {
          for {
            uploadedId <- upload(record)
          } yield uploadedId
        }
      }
    }
    val result2: Future[Seq[Option[Future[String]]]] = Future.sequence(result)
    val result3: Future[Unit] = result2.flatMap { x: Seq[Option[Future[String]]] =>
      Future.sequence(x.flatten).map(notifyUploaded)
    }
    Await.result(result3, Duration.Inf)
  }


  def mapAndFlatMapImpl() = {
    val res: Seq[Future[Iterable[String]]] = ids.map { id =>
      fetch(id).flatMap { maybeRecord =>
        val res1: Option[Future[Seq[String]]] = maybeRecord.map { record =>
          upload(record) map (Seq(_))
        }
        res1 match {
          case Some(a) => a
          case None => Future(Seq())
        }
      }
    }
    val res3: Future[Unit] = Future.sequence(res) map (a => notifyUploaded(a.flatten))
    Await.result(res3, Duration.Inf)
  }
}
对象测试类{
导入scala.concurrent.Future
导入scala.concurrent.ExecutionContext.Implicits.global
导入scala.concurrent_
导入scala.concurrent.duration_
案例类记录(id:字符串)
def fetch(id:String):Future[Option[Record]]=Future{
睡眠(1000);
一些(记录(id))
}
def上传(记录:记录):未来[字符串]=未来{
睡眠(3000);
record.id+“\u已上载”
}
def notifyUploaded(ID:Seq[String]):单位=println(“已通知”+ids)
val ID:Seq[String]=Seq(“a”、“b”、“c”)
def main(参数:数组[字符串]):单位={
用于理解impl()
mapAndFlatMapImpl()
}
def FOREXPRESSIONIMPL()={
val结果:Seq[Future[Option[Future[String]]]]=for{
身份证件
上传(记录)地图(序号)
}
res1匹配{
案例部分(a)=>a
案例无=>Future(Seq())
}
}
}
val res3:Future[Unit]=Future.sequence(res)映射(a=>notifyupload(a.flatten))
wait.result(res3,Duration.Inf)
}
}

单子的可能重复项是内函子范畴中的一个幺半群。只是说,@folone:我担心不是每个人都会得到这个机会。只是说,@folone,但问题是,自然转换是从两个内函子的乘积到自身,而不是它们本身就是内函子。@folone因此,每个单子都是Scala类型范畴内的内函子范畴中的一个对象。在这一类中,态射是函子之间的自然变换,“flatMap/bind”的自然变换是从
mxm->M
,而合成它则类似于
mxt->TM
(例如,函子的合成)。问题是它不能得到保证(通常不是真的)构图本身就是单子。
object TestClass {

  import scala.concurrent.Future
  import scala.concurrent.ExecutionContext.Implicits.global
  import scala.concurrent._
  import scala.concurrent.duration._

  case class Record(id: String)


  def fetch(id: String): Future[Option[Record]] = Future {
    Thread.sleep(1000);
    Some(Record(id))
  }

  def upload(record: Record): Future[String] = Future {
    Thread.sleep(3000);
    record.id + "_uploaded"
  }

  def notifyUploaded(ids: Seq[String]): Unit = println("notified" + ids)

  val ids: Seq[String] = Seq("a", "b", "c")

  def main(args: Array[String]): Unit = {
    forComprehensionImpl()
    mapAndFlatMapImpl()
  }

  def forComprehensionImpl() = {
    val result: Seq[Future[Option[Future[String]]]] = for {
      id <- ids
    } yield {
      for {
        maybeRecord <- fetch(id)
      } yield {
        for {
          record <- maybeRecord
        } yield {
          for {
            uploadedId <- upload(record)
          } yield uploadedId
        }
      }
    }
    val result2: Future[Seq[Option[Future[String]]]] = Future.sequence(result)
    val result3: Future[Unit] = result2.flatMap { x: Seq[Option[Future[String]]] =>
      Future.sequence(x.flatten).map(notifyUploaded)
    }
    Await.result(result3, Duration.Inf)
  }


  def mapAndFlatMapImpl() = {
    val res: Seq[Future[Iterable[String]]] = ids.map { id =>
      fetch(id).flatMap { maybeRecord =>
        val res1: Option[Future[Seq[String]]] = maybeRecord.map { record =>
          upload(record) map (Seq(_))
        }
        res1 match {
          case Some(a) => a
          case None => Future(Seq())
        }
      }
    }
    val res3: Future[Unit] = Future.sequence(res) map (a => notifyUploaded(a.flatten))
    Await.result(res3, Duration.Inf)
  }
}