【问题标题】:Combining List, Future and Option in for-comprehension - scalaz在理解中结合列表、未来和选项 - scalaz
【发布时间】:2016-02-29 17:47:37
【问题描述】:

我有以下问题:

val sth: Future[Seq[T, S]] = for {
  x <- whatever: Future[List[T]]
  y <- x: List[T]
  z <- f(y): Future[Option[S]]
  n <- z: Option[S]
} yield y: T -> n: S

我想让这段代码工作(我想每个人都理解这个想法,因为我添加了类型)。

我所说的“工作”是指我希望保持理解结构并最终实现预期的类型。我知道有一些“丑陋”的方法可以做到,但我想学习如何纯粹地做到这一点:)

当我阅读互联网时,我得出的结论是,我的问题可以通过 monad 转换器和 scalaz 来解决。不幸的是,我找不到一个示例来帮助我更好地理解我应该如何进行。

目前我已经尝试过 scalaz 和 Eff monad 库,但我想我仍然不明白它是如何工作的,因为我无法解决我的问题。

如果有任何帮助,我将不胜感激。

编辑:它应该是序列的未来,也关于我得到它作为函数参数的“任何东西”,抱歉误导你

【问题讨论】:

    标签: scala monads scalaz monad-transformers


    【解决方案1】:

    您可以使用 scalaz ListT monad transformer 执行您需要的操作

     object Test {
       import scalaz._
       import ListT._
       type T = String
       type S = Int
       val whatever: Future[List[T]] = ??? // you get this somewhere
       def f(y: T): Future[Option[S]] = ??? // function that returns future of option
    
       val sth: Future[List[(T, S)]] = (for {
         y <- listT(whatever) 
         // you cannot mix list and option, but you can convert the option to a list of 1 item
         n <- listT(f(y).map(_.toList)) 
       } yield y -> n).run
     }
    

    N.B.:由于你从一个未来开始,你不能返回一个 Seq[(T,S)],你只能有一个未来。如果要阻塞并获取结果,则必须调用 Await.result。

    【讨论】:

    • 谢谢!这非常有帮助,这正是我想要的!为了清楚起见,当我在 for 理解中使用任何带有 T(option/list/etc) 的类型时,我只需要使用其中一种类型就可以工作吗?
    • 是的,就好像你将所有东西都嵌入到了外部 monad 的上下文中(在这种情况下是未来),“内部”monad 仍然必须是相同的,就好像它们都是列表/选项/等。
    【解决方案2】:

    for 理解的问题在于它不是某种神奇的单子“解包器”,它只是 mapflatMapfilter 的序列。

    您可能知道mapflatMap 仅在“内部”类型上运行,而“外部”类型的 monad 保持不变。这意味着你不能这样做:

    for {
      x <- whatever: Future[List[T]]
      y <- x: List[T]
    } yield y
    

    内单for。相反,您可以这样做:

    for (x <- whatever: Future[List[T]])
      yield for (y <- x: List[T]) yield y
    

    看起来有点丑。

    回到你的例子,我更容易使用mapflatMap 来明确地编写整个转换,因为它可以让你更好地了解和控制:

    whatever.flatMap {
      x: List[T] =>
        Future.sequence(x.map {
          y: T => f(y).map(y -> _)
        }).map(_.collect {
          case (y, Some(n)) => y -> n
        })
    }
    

    另外,@trustnoone 提到,如果不明确调用 Await,您将无法摆脱 Future

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-02-03
      • 1970-01-01
      • 2021-04-10
      • 1970-01-01
      • 2017-03-28
      • 1970-01-01
      • 2021-09-18
      相关资源
      最近更新 更多