Failover processing when return type - Option [Error]

I posted a few questions about failover in Scala, and I really thank all of you for your answers.

I understand my options when dealing with Either and Scalaz, or for understanding, and I have another (last?) Question:

How to perform a fault-tolerant sequence of operations when operations deal with an external non-functional world, such as DB?




I mean, I have a method like this:

def insertItem(item: Item): Either[Error,Item] 

Thanks to Either and these answers, I know how to do this with: calls to the chaining method using either , Checking the method parameters in Scala, for understanding and monads

But the case Item class is immutable, and there is no point in returning it as Right , since the caller already has a value.

So how can I do the same with:

 def insertItem(item: Item): Option[Error] 



In my application, when the user is created, we also create some elements for him. If the item cannot be created, then the whole process should stop.

When I use Option[Error] directly for understanding, I don’t think I will get the expected result.

I think it makes sense to do something like this:

 for { _ <- insertItem(item1).toLeft("???").right _ <- insertItem(item2).toLeft("???").right _ <- insertItem(item3).toLeft("???").right } 

But since the meanings are "???" I put in my rights, it’s never useful, I think that I don’t have an elegant solution that is not related to creating rights that will never be used.

I think I'm looking for something that will continue to be understood only when the result is None , which looks strange, because I just want to continue the next operation and not make a real map operation.

By the way, if possible, I would like both non-Scalaz solutions and Scalaz solutions. I'm not sure if Scalaz handles such things because it seems more focused on real functional programming and may not provide code for side effects, like my use case?

+4
scala scalaz
Oct 22 '12 at 16:12
source share
4 answers

I see no fundamental reason not to use Either[Error, Unit] in this case (or at least I did it, and I don’t feel guilty about that). Say we have the following:

 def launch(thing: String): Either[String, Unit] = Either.cond( thing.nonEmpty, println("Launching the " + thing), "Need something to launch!" ) 

We can show that the right projection monad is accordingly lazy:

 scala> for { | _ <- launch("flowers").right | _ <- launch("").right | r <- launch("MISSILES").right | } yield r Launching the flowers res1: Either[String,Unit] = Left(Need something to launch!) 

No rockets are launched at will.




It's worth noting that if you use Option instead of Either , the operation you describe is just the amount specified for the first instance of the monoid for Option (where the add operation is just orElse ). For example, we can write the following using Scalaz 7:

 import scalaz._, Scalaz._ def fst[A](x: Option[A]): Option[A] @@ Tags.First = Tag(x) def launch(thing: String): Option[String] = if (thing.isEmpty) Some( "Need something to launch!" ) else { println("Launching the " + thing) None } 

And now:

 scala> val r: Option[String] = fst(launch("flowers")) |+| fst( | launch("")) |+| fst(launch("MISSILES")) Launching the flowers r: Option[String] = Some(Need something to launch!) 

Once again, no rockets.

+8
Oct 22 '12 at 19:17
source share

We do something similar when I work with a story to quickly work with sending messages, although this is not an idiomatic story:

 def insertItem(item: Item): Validation[Error, Unit] val result = for { _ <- insertItem(item1) _ <- insertItem(item2) _ <- insertItem(item3) } yield Unit 
+3
Oct 22 '12 at 19:21
source share

If you want to combine the methods containing Option[Error] , and only follow the next step, if Option is None , you can use orElse to do this.

+1
Oct 22 '12 at 19:05
source share

If you are only interested in the first failure, instead of Iterator , your choice may be:

 case class Item(i: Int) case class Error(i: Item) val items = Iterator(1,3,7,-5,-2,0) map Item def insertItem(item: Item): Option[Error] = if (item.i < 0) Some(Error(item)) else None scala> val error = (items map insertItem find (_.isDefined)).flatten error: Option[Error] = Some(Error(Item(-5))) 

If insertItem not your only method, you can call them shared with your values:

 val items = Iterator( () => insertItem(i1), () => deleteItem(i2), () => insertItem(i3), () => updateItem(i4)) 
0
Oct 22 '12 at 17:21
source share



All Articles