简体   繁体   中英

Scala's Either not Having `flatMap` & Meaning of Either.left/.right

Looking at Haskell's Either Monad, there's a >>= function.

Prelude Map> let add100 = \x -> Right (x+100 :: Int)

Prelude Map> x
Right 5
Prelude Map> x >>= add100
Right 105

Prelude Map> let y = Left "..." :: Either String Int
Prelude Map> y >>= add100
Left "..."

However, why doesn't Scala's Either[A,B] have a flatMap , ie equivalent to >>= function?

scala> e
res5: Either[String,Int] = Right(1)

scala> e.
asInstanceOf   fold           isInstanceOf   isLeft         isRight
joinLeft       joinRight      left           right          swap
toString

Also, what's the meaning of left and right ?

scala> e.left
res6: scala.util.Either.LeftProjection[String,Int] = LeftProjection(Right(1))

scala> e.right
res7: scala.util.Either.RightProjection[String,Int] = RightProjection(Right(1))

You can either use fold which requires two functions, one for left and one for right, or use the right projection view:

val e: Either[String, Int] = Right(5)

def add100(i: Int): Either[String, Int] = Right(i + 100)

e.fold(identity, add100)  // Right(105)
e.right.flatMap(add100)   // Right(105)

So the projection views allow you to see an Either instance as something that will be mapped through the left or right type. This is explained in the Either scala-doc help file .


If you are familiar with Haskell, the ScalaZ library might be for you, it has its own 'either' abstraction called \\/ (as described here ).

Either can't have a flatMap , because Either is not a monad. Haskell makes it into a monad by favoring one of the two types over the other, but there really is no justification to do so. Either means "this can be one of two types". Period. It does not give any preferential treatment to one of the two types.

If you use Either for error reporting, then it is true that you want it to be biased to one side, but that is only one usecase of many, and hardcoding a single special usecase into a general interface smells of bad design. And for that usecase, you might just as well use Try , which is basically a biased Either .

left and right return a projection of the Either , which is biased to one side.

However, note that the design and usability of Either has been debated very often, and it is indeed not exactly a shining beacon of good API design. Which is one of the reasons why Try and ScalaZ \\/ exist.

Scala's Either type is unbiased. With types like Try , Future , etc, map and flatMap operate on the successful state, but with Either is this is not the case (though Right is often favored for success). If Either has no true successful state, which value should flatMap operate on? Left or Right ? That's left up to you with projections.

left and right are the projections of Either , which are essentially biased versions of Either .

val test: Either[String, Int] = Right(1)

test.right.map(_ + 1) // Right-biased, will map the value to Right(2)

test.left.map(_ + 1)  // Left-biased, will not operate on the value since it's `Right`, therefore returning Right(1) again.

Scala's Either class was redesigned in Scala 2.12. Prior to 2.12, Either was not biased, and didn't implement map and flatMap methods. As the image from the book shows, Either is redesigned in 2.12 to include those methods, so it can now be used in Scala for-expressions as shown.

https://alvinalexander.com/photos/scala-either-left-right-2.12-biased-map-flatmap/

In Scala 2.12 you can you eg this:

for {
 right1 <- either1
 right2 <- either2
} yield (righ1 + right2)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM