Option as a singleton collection - real life use cases

邮差的信 提交于 2019-12-10 18:25:11

问题


The title pretty much sums it up. Option as a singleton collection can sometimes be confusing, but sometimes it allows for an interesting application. I have one example on top of my head, and would like to learn more of such examples.

My only example is running for comprehension on the Option[List[T]]. We can do the following:

val v = Some(List(1, 2, 3))
for {
  list <- v.toList
  elem <- list
} yield elem + 1

Without having Option.toList, it wouldn't be possible to stay in the same for comprehension, and I'd be forced to write something like this:

for {
  list <- v
} yield for {
  elem <- list
} yield elem + 1

The first example is cleaner, and it's an advantage of Option being a collection. Of course, the result type will be different in these 2 examples, but let's assume it doesn't matter for the sake of discussion.

Any other examples? I'd especially like to concentrate on collection-like usage, and not usage of Option's monadic properties - those are pretty much obvious. In other words, map and flatMap functions are out of scope of this question. They're definitely very useful, just coming from elsewhere.


回答1:


I find that working with Option[T] as a collection's main benefit is that you get to use operations defined on a collection, such as map, flatmap, filter, foreach etc. This makes it easier to do operations on a given option, instead of using pattern matching or checking Option[T].isDefined to see if a value exists.

For example, let's take the user repository example from Daniel Westheide blog post about Option[T]:

Say you have a UserRepository object which returns users based on their ID. The user may or may not exist, hence it returns an Option[Person]. Now let's say we want to search a person by id and then filter their age. We can do:

val age: Some[Int] = UserRepository.findById(1).map(_.age)

Now let's say that a Person also has a gender property of type Option[String]. If you wanted to extract that out, you could use map:

val gender: Option[Option[String]] = UserRepository.findById(1).map(_.gender)

But working with nested options isn't too convenient. For that, you have flatMap:

val gender: Option[String] = UserRepository.findById(1).flatMap(_.gender)

And if we want to print out the gender if it exists, we can use foreach:

gender.foreach(println)

You'll find yourself working with scala types that have nested Option[T] fields defined and it's really handy to have collection like methods which help you remove out boilerplate and noise for extracting the actual value out of the operation.

A more real life use case I just encountered the other day was working with the awscala SDK, where I wanted to retrieve an object from S3 storage:

val bucket: Option[Bucket] = s3.bucket(amazonConfig.bucketName)
val result: Option[S3Object] = bucket.flatMap(_.get(amazonConfig.offsetKey))
result.flatMap(s3Object => 
    Source.fromInputStream(s3Object.content).mkString.decodeOption[Array[KafkaOffset]])

So what happens here is that you query the S3 service for a bucket, which may or may not exist. Then, you want to extract an S3Object out of it which actually contains the data, but the API itself returns an Option[S3Object], so it's handy to use flatMap to flat out get an Option[S3Object] instead of Option[Option[S3Object]]. Finally, I want to deserialize the S3Object which actually contains a JSON, and using the Argonaut library, it returns an Option[MyObject], so then again using flatMap to the rescue of extracting the inner option type.

Edit:

As you pointed out, map and flatMap belong to the monadic property of Option[T]. I've written a blog post describing the reduction of two options where the final solution was:

def reduce[T](a: Option[T], b: Option[T], f: (T, T) => T): Option[T] = {
  (a ++ b).reduceLeftOption(f)
}

Which takes advantage of the ++ operator defined on any collection which is also specifically defined on Option[T], being a collection.




回答2:


I'd suggest to take a look at the corresponding chapter of The Neophyte's Guide to Scala. In my experience, most useful use-cases of Option-as-collection are to filter an option and to make flatMap that implicitly filters None values.



来源:https://stackoverflow.com/questions/36933813/option-as-a-singleton-collection-real-life-use-cases

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!