Type projection example from "Scala in Action" (chapter 8)
scala, types
Solution
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!
Problem
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.