I was watching John De Goes "FP to the Max" video. In the code he does something like this to get the implicit object:
object Program {
def apply[F[_]](implicit F: Program[F]): Program[F] = F
}
Does this imply that the variable name F (the first one in implicit F: Program[F]
) is actually a different F
? It is very confusing. Does he mean to do:
object Program {
def apply[F[_]](implicit ev: Program[F]): Program[F] = ev
}
How does the compile know which F
he is referring to while returning the F
? The type constructor or the variable in scope?
Indeed the function parameter T
is different from type parameter T
, for example
def f[T](T: T): T = T
f(42) // res0: Int = 42
Compiler does not get confused because values exist in a different universe from types:
...there exist two separate universes, the universe of types and the universe of values. In the universe of values, we have methods which take values as arguments in round parentheses (or occasionally curly braces). In the universe of types, we have type constructors, which take types as arguments in square brackets.
This convention is sometimes used when dealing with typeclasses. It is meant to communicate that we want to simply return the typeclass instance resolved for F
. To avoid confusion you could use ev
approach you already suggested in question, or even
object Program {
def apply[F[_]: Program]: Program[F] = implicitly[Program[F]]
}
As a side-note, this trick with apply
method in companion object of typeclass allows us to avoid having to use implicitly
, for example, given
trait Foo[T]
trait Bar[T]
trait Program[F[_]]
implicit val fooProgram: Program[Foo] = ???
implicit val barProgram: Program[Bar] = ???
object Program {
def apply[F[_]: Program]: Program[F] = implicitly
}
then we can write
Program[Bar]
instead of
implicitly[Program[Bar]]
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