如何编写在Scala中返回Option [List]的函数? [英] How to compose functions that return Option[List] in Scala?

查看:77
本文介绍了如何编写在Scala中返回Option [List]的函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有两个获取订单和订单商品的功能:

Suppose I have two functions to get orders and order items:


def getOrders(): Option[List[Int]] = ...
def getOrderItems(orderId: Int): Option[List[Int]] = ...

请注意,这两个函数均会返回Option[List],因为每个函数都可能会失败.

Note that both functions return Option[List] since each function may fail.

现在,我想获得所有订单项的List中的Option,如下所示:

Now I would like to get Option of List of all order items as follows:

    如果两个函数都返回Some和,则
  • 返回Some[List]
  • None(如果其中任何一个返回None).
  • return Some[List] if both functions return Some and
  • None if any of them returns None.

我试图用for组合这些功能(见下文),但是没有用.

I tried to compose these functions with for (see below) but it did not work.


val allOrderItems = for {
  orderIds   <- getOrders();
  orderId    <- orderIds;
  orderItems <- getOrderItems(orderId)
} yield orderItems

如何使用功能getOrdersgetOrderItems构建功能getAllOrderItems():Option[List[Int]]?

How can I build a function getAllOrderItems():Option[List[Int]] using functions getOrders and getOrderItems ?

推荐答案

您真的希望能够将Option[List[Option[List[Int]]]]的中间两层翻转过来,以便可以使选项和列表彼此相邻.此操作称为排序,由Scalaz提供:

You really want to be able to turn the middle two layers of Option[List[Option[List[Int]]]] inside out, so that you can get the options and lists next to each other. This operation is called sequencing, and it's provided by Scalaz:

import scalaz._, Scalaz._

val items: Option[List[Int]] =
  getOrders.flatMap(_.map(getOrderItems).sequence).map(_.flatten)

您可以等效地使用traverse,它结合了mapsequence操作:

You could equivalently use traverse, which combines the map and sequence operations:

val items: Option[List[Int]] =
  getOrders.flatMap(_ traverse getOrderItems).map(_.flatten)

如果您不想使用Scalaz,则可以编写自己的(较少多态的)sequence:

If you don't want to use Scalaz, you could write your own (less polymorphic) sequence:

def sequence[A](xs: List[Option[A]]) = xs.foldRight(Some(Nil): Option[List[A]]) {
  case (Some(h), Some(t)) => Some(h :: t)
  case _ => None
}

然后:

val items: Option[List[Int]] = getOrders.flatMap(
  orderIds => sequence(orderIds.map(getOrderItems))
).map(_.flatten)

monad转换解决方案实际上也非常简单(如果您愿意使用Scalaz):

The monad transformation solution is actually pretty straightforward as well (if you're willing to use Scalaz):

val items: Option[List[Int]] = (
  for {
    orderId <- ListT(getOrders)
    itemId  <- ListT(getOrderItems(orderId))
  } yield itemId
).underlying

这种方法的好处是,您不必考虑需要在何处展平,排序等等—普通的旧式monadic操作完全可以满足您的要求.

The nice thing about this approach is that you don't have to think about where you need to flatten, sequence, etc.—the plain old monadic operations do exactly what you want.

这篇关于如何编写在Scala中返回Option [List]的函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆