问题描述:

What is the preferred canonical method in Scala (or FP) of adapting complex chained if...then... statements? For example (metacode):

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

....

}

So far I'm modeling this as a sequence of nested match...case Some...case None returning something like Either[MotivationOfMissingOrderReturned,OrderWithAllDetails]

But I'm unsure if this is the best approach (it looks to me a bit ugly and difficult to read) or maybe I can model it with some kind of chained monad flow like Try or map / filter, Futures, maybe using elegant for comprehensions.

I'm new in FP and trying to grasp how to methodically convert my non-functional instinct into FP jargon.

I know that FP tends to avoid using if... then ... else in favour of collective actions made on containers like Option, List and other monads.

网友答案:

One way is pattern matching:

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
}

Another is through a for-comprehension

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... }

Which really boils down to a bunch of flatMaps

So, it depends on your preference. I often feel that pattern matching or for comprehensions are more readable to a larger audience of developers, but it depends on the situation.

But, ultimately, most of this relies on using the right data structures. IE. the above example fits best with Option, Disjunction, or Validation.

网友答案:

If you use Option, you can put that all together as a for-comprehension.

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
  }
}
相关阅读:
Top