trait Functor[F[_]]:
extension[A] (fa: F[A])
def map[B](f: A => B): F[B]
trait Applicative[F[_]: Functor]:
def pure[A](a: A): F[A]
extension[A, B] (fab: F[A => B])
def ap(fa: F[A]): F[B]
object Applicative:
def pure[A, F[_]](a: A)(using ap: Applicative[F]): F[A] = ap.pure(a)
@targetName("apFirst")
def <*[A, B, F[_]: Applicative](fa: F[A], fb: F[B]): F[A] = fa.map(a => (_: B) => a).ap(fb)
Error: value map is not a member of type F in <*.
I get error in the last function. If I add Functor constraint it works, but shouldn’t it work without that since I constrained it in the Applicative definition? What am I missing?
>Solution :
Type class inheritance is a normal inheritance:
trait Functor[F[_]]:
extension[A] (fa: F[A])
def map[B](f: A => B): F[B]
trait Applicative[F[_]] extends Functor[F]:
def pure[A](a: A): F[A]
extension[A, B] (fab: F[A => B])
def ap(fa: F[A]): F[B]
extension[A] (fa: F[A])
override def map[B](f: A => B): F[B] = pure(f).ap(fa)
Be cautious when you use it though, as having 2 type classes having the same parent will result in conflicting instances:
trait TypeClass1[A]
def method: A
object TypeClass1:
def method[A: TypeClass1]: A = summon[TypeClass1[A]].method
trait TypeClass2[A] extends TypeClass1[A]:
def method2: A
override def method: A = method2
trait TypeClass3[A] extends TypeClass1[A]:
def method3: A
override def method: A = method3
def usage[A: TypeClass2: TypeClass3] =
TypeClass1.method[A] // ambiguous implicit
This issue can be seen in some Cats Effect 2 type class hierarchy.
When you define things like this:
trait Functor[F[_]]:
extension[A] (fa: F[A])
def map[B](f: A => B): F[B]
trait Applicative[F[_]: Functor]:
def pure[A](a: A): F[A]
extension[A, B] (fab: F[A => B])
def ap(fa: F[A]): F[B]
then the inside of Applicative[F] sees that F is a Functor and has access to .map… but F : Functor is a constraint, not a proper type bound. It desugars to (using Functor[F]) which is merely an argument to a constructor (or other method), not something which extends interface nor encodes in its type any information about inheritance. As far as the outside of Applicative is concerned in such code there is no relationship between Functor[F] and Applicative[F].