Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type projection example from "Scala in Action" (chapter 8)

Tags:

types

scala

could anyone help me with below code bits from the book?

trait Mapper[F[_]] {
  def fmap[A, B](xs: F[A], f: A => B): F[B]   
}

def VectorMapper = new Mapper[Vector] {
  def fmap[A, B](xs: Vector[A], f: A => B): Vector[B] = xs map f 
}

That was simple: trait definition using higher-kinded type F[_] for usage with any "container-like" types, then a concrete mapper for Vector.

Then goes a tricky part. Mapper for Either. I understand {type E[A] = Either[X, A]} just as a block of code, and ({type E[A] = Either[X, A]})#E as a projection that takes that type alias E out of the anonymous block of code and by that author "hides" the presence of X for the Mapper trait because trait operates on single type parameter "container types" only - and we are interested in A, i.e. Right.

def EitherMapper[X] = new Mapper[({type E[A] = Either[X, A]})#E ] {
    def fmap[A, B](r: Either[X, A], f: A => B): Either[X, B] = r match {
        case Left(a) => Left(a)
        case Right(a) => Right(f(a))
    }     
}

Question: Why do we need X in the def EitherMapper[X] = part?

Thanks for details.

like image 957
Max Avatar asked Oct 04 '22 06:10

Max


1 Answers

Either is dependent on two types, for instance Either[Int, String]

EitherMapper is a type constructor that is dependent just on one type, so when you have a EitherMapper[Int], you are dealing with a Either[Int, A], and A is resolved into the Mapper part, this way you can have any A=>B function, because the first type of Either is already present for the Mapper and you return a Either[X, B].

Indeed the type E[A] is equivalent to Either[X, A], you have just one degree of freedom regarding to types!

val right: Either[Boolean, String] = Right("test")
val left: Either[Boolean, String] = Left(false)

println(EitherMapper.fmap(right, (s: String) => s.length))
> Right(4)
println(EitherMapper.fmap(left, (s: String) => s.length))
> Left(false)

In this case the type is EitherMapper[Boolean] and the type of fmap is fmap[String, Integer], it accepts Either[Boolean, String] and return Either[Boolean, Integer].

As you can see the type of fmap doesn't say anything on the X part of the Either[X, A] type so in the end you could use the (s: String) => s.length) function for others EitherMapper[X] types, in simple words the "left" part of the either type can be anything you want, and it's the "X" part of the type construction.

Hope it's clearer now!

like image 75
Vincenzo Maggio Avatar answered Oct 07 '22 17:10

Vincenzo Maggio