Scala 编程:将 if else 序列转换为 map 流的规范方法

Scala Programming: Canonical way to convert a sequence of if else into a flow of map

Scala(或 FP)中适应复杂链式 if...then... 语句的首选规范方法是什么?例如(元代码):

def fetchLastOrderFor(CustomerId:UUID)= {
    fetch Customer data from an Id
    if Customer exists 
       fetch extra information for that customer (address?)
       fetch latest order of that customer
       if Order exists
          fetch OrderDetails
          ....
}

到目前为止,我将其建模为嵌套的 match...case Some...case None 返回类似 Either[MotivationOfMissingOrderReturned,OrderWithAllDetails]

的序列

但我不确定这是否是最好的方法(在我看来它有点难看且难以阅读)或者我可以使用某种链式 monad 流对其进行建模,例如 Trymap / filter, Futures, 也许使用优雅的 for 理解。

我是 FP 的新手,正在尝试掌握如何有条不紊地将我的非功能性本能转化为 FP 行话。

我知道 FP 倾向于避免使用 if... then ... else 以支持对 OptionList 和其他 monad 等容器进行集体操作。

一种方式是模式匹配:

def fetchLastOrderFor(CustomerId:UUID)= {
customer = fetch Customer data from an Id
customer match{
  case Some(custData) => {
    info = fetch extra information for that customer (address?)
    lastOrder = fetch latest order of that customer
    lastOrder match{
      case Some(orderData) => ...
      case None => return invalid 
    }
  }
  case None => return invalid
}

还有一个是通过求理解

def fetchLastOrderFor(CustomerId:UUID)= {
for{
  customer <- fetch Customer data from an Id
  info <- fetch extra information for that customer (address?)
  lastOrder <- fetch latest order of that customer
} yield { ...return some combination of the data above... }

这真的可以归结为一堆 flatMaps

所以,这取决于你的喜好。我经常觉得模式匹配或理解对于更多的开发人员来说更具可读性,但这要视情况而定。

但是,最终,其中大部分都依赖于使用正确的数据结构。 IE。上面的例子最适合 Option、Disjunction 或 Validation。

如果你使用Option,你可以把它们放在一起作为理解。

def getCustomer(id: UUID): Option[Customer] = ???
def getCustomerInfo(customer: Customer): Option[CustomerInfo] = ???
def latestOrderForCustomer(customer: Customer): Option[Order]
def getOrderDetails(order: Order): Option[OrderDetails] = ???

def fetchLastOrderFor(customerId:UUID): Option[OrderDetails] = {
  for {
    customer     <- getCustomer(customerId)
    info         <- getCustomerInfo(customer)
    latestOrder  <- latestOrderForCustomer(customer)
    orderDetails <- getOrderDetails(order)
  } yield {
    orderDetails
  }
}