import cats._
import cats.data._
import cats.implicits._
import scala.concurrent._
import duration.Duration._
import ExecutionContext.Implicits.global
object Sk extends App {
val PLUS = ((_: Int) + (_: Int)).curried
trait SK[F[_]] {
def S[E, A, B]: Kleisli[F, E, A => B] =>
Kleisli[F, E, A] => Kleisli[F, E, B]
def K[E, A]: (E => A) => Kleisli[F, E, E => A]
def I[A]: Kleisli[F, A, A]
}
object SK {
def apply[F[_] : SK] = implicitly[SK[F]]
}
implicit def ska[F[_] : Applicative]: SK[F] =
new SK[F] {
def AP[E] = Applicative[Kleisli[F, E, ?]]
def S[E, A, B] = AP[E].ap[A, B]
def K[E, A] = AP[E].pure[E => A]
def I[A] = Kleisli.ask[F, A]
}
def answer[F[_] : SK] = {
val sk = SK[F]
import sk._
S(S(K(PLUS))(I))(I)
}
def main[F[_] : SK : Functor] =
answer[F].map(println)
main[Id].apply(21)
Await.ready(main[Future].apply(21), Inf)
}