How to read this flatMap code?

时光怂恿深爱的人放手 提交于 2019-12-25 08:53:57

问题


I'm having trouble deciphering the following function. Particularly, the flatMap line - where are the 'aa' and 'bb; variables coming from, and how is this executed? Maybe if someone could explain in words what is happening with this code it would be helpful. I'm just really struggling how to read this syntax.

def map2[EE >: E, B, C](b: Either[EE, B])(f: (A, B) => C): Either[EE, C] = 
    this flatMap(aa => b map (bb => f(aa, bb)))

Here is the flatMap function:

 def flatMap[EE >: E, B](f: A => Either[EE, B]): Either[EE, B] = this match {
   case Right(r) => f(r)
   case Left(e) => Left(e)
 }

and map:

def map[B](f: A => B): Either[E, B] = this match {
   case Right(r) => Right(f(r))
   case Left(e) => Left(e)
 }

回答1:


Looks like all these functions are defined for Either class. Either can be in two 'states' - Right - correct value and Left which interpreted ass error.

Lets go from the map definition. We have Either parametrized with type A. map accepts function converting type A to B. So map function checks if value is Right then it applies given function f to Right value, wraps it with Right and return. If error then just return error.

Right[String, Int](4).map(_*3)      // gives Right(12)
Left[String, Int]("error").map(_*3) // gives Left("error")

flatMap is similar to map, but accepts function converting type A to Either of right type B, so unlike map we don't need to wrap right value

Right[String, Int](5).flatMap(item => Right(item*3))        //gives Right(15)
Left[String, Int]("error").flatMap(item => Right(item*3))   //gives Left("error")

As defined, map2 takes instance of Either b and function, converting pair of values of types A and B to some third value C, and return the result wrapped with Either. Let's take closer look at how it is implemented.

this.flatMap(aa => b map (bb => f(aa, bb)))       

lets rewrite it with definition of flatMap:

this.match {
  case Right(r) => b.map (bb => f(r, bb))
  case Left(e) => Left(e)
}

And apply map:

this.match {
  case Right(r) => {
    b match {
      case Right(br) => Right(f(r, br))
      case Left(be) => Left(be)
    }
  }
  case Left(e) => Left(e)
}

So there are three paths:

if right a and right b then apply function(a,b)
if right a and error b then error(b)
if error a then error a

Examples:

Right(7).map2(Right(4)){case (a,b) => a*b} // gives Right(28)
Right(7).map2(Left[String, Int]("failed")){case (a,b) => a*b}  //gives Left("failed")
Left[String, Int]("error").map2(Left[String, Int]("failed")){case (a,b) => a*b}  //gives Left("error")

Edit: Inner function explanation

You have to pass to a flatMap function with type:

A => Either[EE, C]

It means "take an argument of type A and convert it to result of type Either[EE,C]"

so you could define:

def map2[EE >: E, B, C](b: Either[EE, B])(f: (A, B) => C): Either[EE, C] = {     
  def func(aa:A):Either[EE, C] = {
     b map (bb => f(aa, bb))
  }
  this flatMap(func)
}


来源:https://stackoverflow.com/questions/34033746/how-to-read-this-flatmap-code

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