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.
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!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With