Reputation: 23
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
, Future
s, 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.
Upvotes: 0
Views: 128
Reputation: 7257
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
}
}
Upvotes: 1
Reputation: 67135
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 flatMap
s
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.
Upvotes: 2