package applicative import scala.language.higherKinds trait Applicative[F[_]] { def unit[A](a: A): F[A] def ap[A, B](ff: F[A => B])(fa: F[A]): F[B] = map2(ff, fa)((f, a) => f(a)) // implement map using unit and ap, but not flatMap/flatten def map[A, B](fa: F[A])(f: A => B): F[B] = ??? // implement map2 using unit and ap // hint: f.curried converts `(A,B) => C` to `A => (B => C)` def map2[A, B, C](fa: F[A], fb: F[B])(f: (A, B) => C): F[C] = ??? // implement unit first // then write the signature for ap and map2 // then implement one of them def compose[G[_]](implicit G: Applicative[G]): Applicative[Lambda[a => F[G[a]]]] = { val F = this new Applicative[Lambda[a => F[G[a]]]] { def unit[A](a: A): F[G[A]] = ??? //note: when you are done implementing this, the test for ap/map2 will result in a StackOverflow until you implement one of them // override def ap... = ??? // or // override def map2... = ??? } } }