I'm learning Cats from scala-exercises.
Wonder how to use high order type, there are some attempt with it:
trait Functor[F[_]] {
def map[A, B](fa: F[A])(f: A => B): F[B]
}
def someThingFail1[In]() = new Functor[Function1[In, _]] {
override def map[A, B](fa: Function1[In, A])(f: A => B): Function1[In, B] = ???
}
def someThingFail2[In]() = new Functor[Either[In, _]] {
override def map[A, B](fa: Either[In, A])(f: A => B): Either[In, B] = ???
}
def someThingFail3() = new Functor[List[_]] {
override def map[A, B](fa: List[A])(f: A => B): List[B] = ???
}
//only this one can compile
def someThingRight1() = new Functor[List] {
override def map[A, B](fa: List[A])(f: A => B): List[B] = ???
}
ahead of three function can't compiled, error message like this:
[error] /Users/lorancechen/version_control_project/_tutorials/learn-cats/src/main/scala/mycats/Main.scala:16:42: Either[In, _] takes no type parameters, expected: one
[error] def someThingFail2[In]() = new Functor[Either[In, _]] {
[error] ^
Why Scala not support type hole? Will Dotty compiler support it? Thanks
That's because in Scala 2.x
Either[X, _]
is an existential type, it can be written out explicitly as
Either[X, Y] forSome { type Y }
This is somewhat similar to Java's wildcards, and not what you want as an argument for a higher order Functor
type constructor. What you want is a type lambda. Originally, this could be written down as follows:
({type lam[Y] = Either[X, Y]})#lam
The fact that type lambdas could be used in Scala at all was not a planned feature, but rather an accidental discovery, and the syntax was somewhat lengthy. However, there is the non/kind-projector plugin that simplifies it dramatically. With this plugin, you code becomes:
trait Functor[F[_]] {
def map[A, B](fa: F[A])(f: A => B): F[B]
}
def someThingFail1[In]() = new Functor[Function1[In, ?]] {
override def map[A, B](fa: Function1[In, A])(f: A => B): Function1[In, B] = ???
}
def someThingFail2[In]() = new Functor[Either[In, ?]] {
override def map[A, B](fa: Either[In, A])(f: A => B): Either[In, B] = ???
}
def someThingFail3() = new Functor[List[?]] {
override def map[A, B](fa: List[A])(f: A => B): List[B] = ???
}
//only this one can compile
def someThingRight1() = new Functor[List] {
override def map[A, B](fa: List[A])(f: A => B): List[B] = ???
}
(Tested with scala 2.12.4, cats 1.0.1, kind-projector 0.9.4).
Note that this plugin is used in cats source code (search for ?
).
Everything will become much better in dotty, it already supports a neat syntax for type lambdas.
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