Why doesn't the Scala Either.RightProjection # filter return?

Using Scala 2.9.1, consider the following two examples of Either :

 scala> val er: Either[String, Int] = Right(1) er: Either[String,Int] = Right(1) scala> val el: Either[String, Int] = Left("a") el: Either[String,Int] = Left(a) 

It’s good that, using the left and right projections, you can use for understanding (through the biased monad of the projected Either):

 scala> for { r <- er.right } yield r * 2 res6: Product with Either[String,Int] with Serializable = Right(2) scala> for { r <- el.right } yield r * 2 res7: Product with Either[String,Int] with Serializable = Left(a) 

Can someone explain to me why it was decided not to return the filter method? I expected the following to work:

 scala> for { r <- er.right if r > 2 } yield r * 2 // r is NOT greater than 2! res8: Product with Either[String,Int] with Serializable = Left(a) 

Instead, you get the following error:: 9: error: the value * is not a member Either [Nothing, Int] for {r <er.right if r> 2} gives r * 2

It seems that the main call to Either.RightProjection#filter really returns Option :

 scala> er.right.filter(_ > 2) res9: Option[Either[Nothing,Int]] = None 

This defeats the use of the if clause in understanding, at least, how I tried to use it.

Does anyone have an explanation why this design is the way it is?

+6
source share
1 answer

It comes down to the fact that if you have Right(b) but the filter predicate fails, you have no value for entering Left .

You can imagine an implementation that works for your case Either[String, Int] without fulfilling the default value Left("") . The Scala standard library does not have the ability to create a value for you, because it does not include a concept, such as a monoid, that will define an "empty" value for a type.

The Scalaz library includes a monoid class, and version 7 also includes a shift type with a right shift, \/[A, B] (isomorphic to Either[A, B] ), which has a filter method if the left type is a monoid:

 scala> \/.right[String, Int](1).filter(_ > 2) res1: scalaz.\/[String,Int] = -\/() 

But you could not do this for the general case - if you have Either[Nothing, Int] , you can never create a left value.

+11
source

All Articles