user3899879
user3899879

Reputation: 257

How to FlatMap Option while Preserving When Empty

I would like to flatmap option transformations, while having visibility into where the transformation "dropped out" (that is, where a None is first returned).

Some sample code:

val stringFetcher : DomainObject=>Option[String] = ...

val filterer : String=>Option[String] = ...

val reportFilteredCause: DomainObject => String = do =>
{
   val strOption = stringFetcher(do)
   val filterReasonOption = strOption flatMap filterer
   filterReasonOption.getOrElse("Failed to fetch string representation OR field not filtered")
}

Ideally, I'd like to write something like below, where I pass in some reporting string associated with every Option transformation:

val stringFetcher : DomainObject=>Option[String] = ...

val filterer : String=>Option[String] = ...

val reportFilteredCause: DomainObject => String = do =>
{
   val strOption : Either[Option[String], String]] = EitherWrapper stringFetcher(do) "Failed to fetch string representation"
   val filterReasonOption = strOption flatMapWrapper filterer "Failed to filter field
   filterReasonOption
}

Upvotes: 1

Views: 706

Answers (1)

jwvh
jwvh

Reputation: 51271

I think what you want is an Either[String,String] where the left projection is the failure message and the right projection is the result string.

val reportFilteredCause :DomainObject => String = { dob :DomainObject =>

  val strOption :Either[String, String] =
    stringFetcher(dob).toRight("Failed to fetch string representation")

  val filterReasonOption :Either[String,String] =
    strOption.flatMap(filterer(_).toRight("Failed to filter field"))

  filterReasonOption.fold(identity,identity)
}

The .toRight() method transforms an Option into an Either:

Some(x).toRight(y) //x.right
None.toRight(y)    //y.left

Although, in truth, it's probably easier and clearer to use fold() and getOrElse().

val reportFilteredCause :DomainObject => String = {
  stringFetcher(_).fold("Failed to fetch string representation"){
   filterer(_).getOrElse("Failed to filter field")
  }
}

Upvotes: 3

Related Questions