diff --git a/modules/kernel/higherKind/src/main/scala/tofu/syntax/functionK.scala b/modules/kernel/higherKind/src/main/scala-2/tofu/syntax/functionK.scala similarity index 100% rename from modules/kernel/higherKind/src/main/scala/tofu/syntax/functionK.scala rename to modules/kernel/higherKind/src/main/scala-2/tofu/syntax/functionK.scala diff --git a/modules/kernel/higherKind/src/main/scala-3/tofu/syntax/functionK.scala b/modules/kernel/higherKind/src/main/scala-3/tofu/syntax/functionK.scala new file mode 100644 index 000000000..a0e8b525f --- /dev/null +++ b/modules/kernel/higherKind/src/main/scala-3/tofu/syntax/functionK.scala @@ -0,0 +1,33 @@ +package tofu.syntax + +import cats.~> + +object funk { + + def makeFunctionK[F[_], G[_]](maker: ContextNT[F, G]): F ~> G = toFunK(maker) + + def funK[F[_], G[_]](maker: ContextNT[F, G]) = toFunK(maker) + + def funKFrom[F[_]] = new Applied1[F](true) + + type ContextNT[F[_], G[_]] = (arb: { type _A }) ?=> F[arb._A] => G[arb._A] + + private def toFunK[F[_], G[_]](maker: ContextNT[F, G]): F ~> G = + new ~>[F, G] { + def apply[A](fa: F[A]): G[A] = + given { type _A = A } = new { type _A = A } + maker(fa) + } + + final class Applied1[F[_]](private val __ : Boolean) extends AnyVal { + def apply[G[_]](maker: ContextNT[F, G]): F ~> G = + toFunK[F, G](maker) + } + + // RepresentableK uses Maker + abstract class Maker[F[_], G[_], Arbitrary] extends (F ~> G) { + def applyArbitrary(f: F[Arbitrary]): G[Arbitrary] + + def apply[A](fa: F[A]): G[A] = applyArbitrary(fa.asInstanceOf[F[Arbitrary]]).asInstanceOf[G[A]] + } +} diff --git a/modules/kernel/higherKind/src/test/scala/tofu/syntax/functionKSpec.scala b/modules/kernel/higherKind/src/test/scala/tofu/syntax/functionKSpec.scala new file mode 100644 index 000000000..ea38b14dc --- /dev/null +++ b/modules/kernel/higherKind/src/test/scala/tofu/syntax/functionKSpec.scala @@ -0,0 +1,26 @@ +package tofu.syntax + +import org.scalatest.funsuite.AnyFunSuite +import cats.{Id, ~>} + +class functionKSpec extends AnyFunSuite { + def infer1(x: Id ~> Option): Unit = () + + test("funK infers type args") { + assertCompiles( + """|import tofu.syntax.funk._ + |infer1(funK(Some(_))) + |""".stripMargin + ) + } + + def infer2[F[_]](x: F ~> Option): Unit = () + + test("funKFrom infers type args") { + assertCompiles( + """|import tofu.syntax.funk._ + |infer2(funKFrom[Id](Some(_))) + |""".stripMargin + ) + } +}