From 0e6392f62002d9164393a1562d13f347e2a2060e Mon Sep 17 00:00:00 2001 From: Oleg Nizhnik Date: Mon, 10 Feb 2020 20:00:47 +0300 Subject: [PATCH 1/3] representable derivation --- build.sbt | 2 +- .../tofu/higherKind/derived/EmbedKSuite.scala | 2 + .../derived/RepresentableKSuite.scala | 40 +++++-- .../main/scala/tofu/higherKind/Embed.scala | 30 +----- .../tofu/higherKind/RepresentableK.scala | 101 +++++++++++++++++- .../derived/HigherKindedMacros.scala | 34 +++--- 6 files changed, 156 insertions(+), 53 deletions(-) diff --git a/build.sbt b/build.sbt index 09b291c1d..8928f3f0a 100644 --- a/build.sbt +++ b/build.sbt @@ -185,7 +185,7 @@ lazy val derivation = defaultSettings, libraryDependencies ++= Seq(magnolia, derevo, catsTagless), macros, - publishName := "derivation" + publishName := "derivation", ) .dependsOn(data) diff --git a/derivation/src/test/scala/tofu/higherKind/derived/EmbedKSuite.scala b/derivation/src/test/scala/tofu/higherKind/derived/EmbedKSuite.scala index 5fd1ef2cf..acb8a21f0 100644 --- a/derivation/src/test/scala/tofu/higherKind/derived/EmbedKSuite.scala +++ b/derivation/src/test/scala/tofu/higherKind/derived/EmbedKSuite.scala @@ -1,4 +1,5 @@ package tofu.higherKind.derived +import cats.data.{IorT, NonEmptyChain} import cats.free.Free import derevo.derive import tofu.higherKind.Embed @@ -8,6 +9,7 @@ object EmbedKSuite { trait Foo[F[_]] { def foo(x: Int, s: String): F[Double] def bar(a: List[Int]): Free[F, Unit] + def baz(xx: Double): IorT[F, NonEmptyChain[String], Long] } Embed[Foo] diff --git a/derivation/src/test/scala/tofu/higherKind/derived/RepresentableKSuite.scala b/derivation/src/test/scala/tofu/higherKind/derived/RepresentableKSuite.scala index aa880ed56..a87aab061 100644 --- a/derivation/src/test/scala/tofu/higherKind/derived/RepresentableKSuite.scala +++ b/derivation/src/test/scala/tofu/higherKind/derived/RepresentableKSuite.scala @@ -1,21 +1,19 @@ package tofu.higherKind.derived -import cats.data.Tuple2K +import RepresentableKSuite.Foo +import cats.data.{OptionT, Tuple2K} import cats.instances.either._ import cats.syntax.either._ import cats.syntax.functor._ -import cats.{Id, ~>} -import org.scalatest.{FlatSpec, Matchers} -import tofu.data.Embedded -import RepresentableKSuite.Foo -import tofu.syntax.functionK.funK -import tofu.syntax.embed._ import cats.tagless.syntax.functorK._ import cats.tagless.syntax.semigroupalK._ -import cats.tagless.syntax.applyK._ +import cats.{Id, ~>} import derevo.derive -import tofu.higherKind.derived.representableK +import org.scalatest.{FlatSpec, Matchers} +import tofu.data.Embedded +import tofu.higherKind.{RepK, RepresentableK} import tofu.syntax.embed._ +import tofu.syntax.functionK.funK import scala.util.Try @@ -25,11 +23,13 @@ class RepresentableKSuite extends FlatSpec with Matchers { Try(s.toDouble).toEither.left.map(_ => s"could not parse $s as double").map(_ * x) override def bar(a: List[Int]): Either[String, Unit] = a.headOption.toRight("must contain at least one element").void + def baz(a: List[Int]): OptionT[Either[String, *], Unit] = OptionT.liftF(Left("hello")) } val defaultFoo: Foo[Id] = new Foo[Id] { override def foo(x: Int, s: String): Double = x.toDouble override def bar(a: List[Int]): Unit = () + def baz(a: List[Int]): OptionT[Id, Unit] = OptionT.none } "representableK" should "generate nice mapK" in { @@ -82,6 +82,28 @@ object RepresentableKSuite { @derive(representableK) trait Foo[F[_]] { def foo(x: Int, s: String): F[Double] + def bar(a: List[Int]): F[Unit] + + def baz(a: List[Int]): OptionT[F, Unit] + } + + trait Foo1[F[_]] { + def foo(x: Int, s: String): F[Double] + + def bar(a: List[Int]): F[Unit] + + def baz(a: List[Int]): OptionT[F, Unit] + } + + new RepresentableK[Foo1] { + def tabulate[F[_]](hom: RepK[Foo1, *] ~> F): Foo1[F] = new Foo1[F] { + def foo(x: Int, s: String): F[Double] = hom(RepK.mk(_.foo(x, s))) + def bar(a: List[Int]): F[Unit] = hom(RepK.mk(_.bar(a))) + def baz(a: List[Int]): OptionT[F, Unit] = { + val OT = RepresentableK[OptionT[*[_], Unit]] + OT.tabulate[F](funK(rep => hom(RepK[Foo1](foo => rep(foo.baz(a)))))) + } + } } } diff --git a/higherKindCore/src/main/scala/tofu/higherKind/Embed.scala b/higherKindCore/src/main/scala/tofu/higherKind/Embed.scala index 87a020854..74e4aa394 100644 --- a/higherKindCore/src/main/scala/tofu/higherKind/Embed.scala +++ b/higherKindCore/src/main/scala/tofu/higherKind/Embed.scala @@ -1,10 +1,8 @@ package tofu.higherKind import cats.FlatMap -import cats.data.{EitherT, IorT, OptionT, ReaderT, WriterT} import cats.free.Free import simulacrum.typeclass -import tofu.syntax.monadic._ @typeclass trait Embed[U[_[_]]] { def embed[F[_]: FlatMap](ft: F[U[F]]): U[F] @@ -19,37 +17,13 @@ trait EmbedInstanceChain[TC[u[_[_]]] >: Embed[u]] extends RepresentableKInstance def embed[F[_]: FlatMap](ft: F[Free[F, A]]): Free[F, A] = Free.roll(ft) } - private[this] def optionTInstance[A]: Embed[OptionT[*[_], A]] = new Embed[OptionT[*[_], A]] { - def embed[F[_]: FlatMap](ft: F[OptionT[F, A]]): OptionT[F, A] = OptionT(ft.flatMap(_.value)) - } - private[this] def eitherTInstance[E, A]: Embed[EitherT[*[_], E, A]] = new Embed[EitherT[*[_], E, A]] { - def embed[F[_]: FlatMap](ft: F[EitherT[F, E, A]]): EitherT[F, E, A] = EitherT(ft.flatMap(_.value)) - } - private[this] def writerTInstance[W, A]: Embed[WriterT[*[_], W, A]] = new Embed[WriterT[*[_], W, A]] { - def embed[F[_]: FlatMap](ft: F[WriterT[F, W, A]]): WriterT[F, W, A] = WriterT(ft.flatMap(_.run)) - } - private[this] def iorTInstance[E, A]: Embed[IorT[*[_], E, A]] = new Embed[IorT[*[_], E, A]] { - def embed[F[_]: FlatMap](ft: F[IorT[F, E, A]]): IorT[F, E, A] = IorT(ft.flatMap(_.value)) - } + private[this] val freeEmbedAny = freeInstance[Any] - private[this] def readerTInstance[R, A]: Embed[ReaderT[*[_], R, A]] = new Embed[ReaderT[*[_], R, A]] { - def embed[F[_]: FlatMap](ft: F[ReaderT[F, R, A]]): ReaderT[F, R, A] = ReaderT(r => ft.flatMap(_.run(r))) - } - private[this] val freeEmbedAny = freeInstance[Any] - private[this] val optionTEmbedAny = optionTInstance[Any] - private[this] val eitherTEmbedAny = eitherTInstance[Any, Any] - private[this] val writerTEmbedAny = writerTInstance[Any, Any] - private[this] val iorTEmbedAny = iorTInstance[Any, Any] - private[this] val readerTEmbedAny = readerTInstance[Any, Any] final implicit def freeEmbed[A]: TC[Free[*[_], A]] = freeEmbedAny.asInstanceOf[TC[Free[*[_], A]]] - final implicit def optionEmbed[A]: TC[OptionT[*[_], A]] = optionTEmbedAny.asInstanceOf[TC[OptionT[*[_], A]]] - final implicit def eitherTEmbed[E, A]: TC[EitherT[*[_], E, A]] = eitherTEmbedAny.asInstanceOf[TC[EitherT[*[_], E, A]]] - final implicit def writerTEmbed[W, A]: TC[WriterT[*[_], W, A]] = writerTEmbedAny.asInstanceOf[TC[WriterT[*[_], W, A]]] - final implicit def iorTEmbed[E, A]: TC[IorT[*[_], E, A]] = iorTEmbedAny.asInstanceOf[TC[IorT[*[_], E, A]]] - final implicit def readerTEmbed[R, A]: TC[ReaderT[*[_], R, A]] = readerTEmbedAny.asInstanceOf[TC[ReaderT[*[_], R, A]]] + } diff --git a/higherKindCore/src/main/scala/tofu/higherKind/RepresentableK.scala b/higherKindCore/src/main/scala/tofu/higherKind/RepresentableK.scala index 023624da4..ba5dd1331 100644 --- a/higherKindCore/src/main/scala/tofu/higherKind/RepresentableK.scala +++ b/higherKindCore/src/main/scala/tofu/higherKind/RepresentableK.scala @@ -1,5 +1,6 @@ package tofu.higherKind -import cats.data.Tuple2K +import cats.data.{EitherT, IorT, OptionT, ReaderT, Tuple2K, WriterT} +import cats.free.Cofree import cats.tagless.IdK import cats.{FlatMap, ~>} import simulacrum.typeclass @@ -12,6 +13,7 @@ trait RepK[U[_[_]], A] { object RepK { def apply[U[_[_]]] = new Applied[U](true) + def mk[U[_[_]]] = new Applied[U](true) class Applied[T[_[_]]](private val __ : Boolean) extends AnyVal { type Arb[_] @@ -58,7 +60,102 @@ trait RepresentableKInstanceChain[TC[u[_[_]]] >: RepresentableK[u]] { override def pureK[F[_]](p: Point[F]): F[A] = p.point[A] } - private[this] val idKRepresentableAny = idKRepresentableInst[Any] + private[this] def readerTInstance[R, A]: RepresentableK[ReaderT[*[_], R, A]] = + new RepresentableK[ReaderT[*[_], R, A]] { + def tabulate[F[_]](hom: RepK[ReaderT[*[_], R, A], *] ~> F): ReaderT[F, R, A] = ReaderT(r => hom(RepK.mk(_.run(r))) + ) + override def embed[F[_]: FlatMap](ft: F[ReaderT[F, R, A]]): ReaderT[F, R, A] = ReaderT(r => ft.flatMap(_.run(r))) + override def pureK[F[_]](p: Point[F]): ReaderT[F, R, A] = ReaderT(r => p.point[A]) + override val unitK: ReaderT[UnitK, R, A] = super.unitK + override def mapK[F[_], G[_]](af: ReaderT[F, R, A])(fk: F ~> G): ReaderT[G, R, A] = af.mapK(fk) + + override def productK[F[_], G[_]](af: ReaderT[F, R, A], ag: ReaderT[G, R, A]): ReaderT[Tuple2K[F, G, *], R, A] = + ReaderT(r => Tuple2K(af.run(r), ag.run(r))) + + override def zipWith2K[F[_], G[_], H[_]](af: ReaderT[F, R, A], ag: ReaderT[G, R, A])( + f2: Function2K[F, G, H] + ): ReaderT[H, R, A] = ReaderT(r => f2(af.run(r), ag.run(r))) + } + + private[this] def optionTInstance[A]: RepresentableK[OptionT[*[_], A]] = new RepresentableK[OptionT[*[_], A]] { + def tabulate[F[_]](hom: RepK[OptionT[*[_], A], *] ~> F): OptionT[F, A] = OptionT(hom(RepK.mk(_.value))) + + override def mapK[F[_], G[_]](af: OptionT[F, A])(fk: F ~> G): OptionT[G, A] = af.mapK(fk) + override def productK[F[_], G[_]](af: OptionT[F, A], ag: OptionT[G, A]): OptionT[Tuple2K[F, G, *], A] = + OptionT(Tuple2K(af.value, ag.value)) + override def zipWith2K[F[_], G[_], H[_]](af: OptionT[F, A], ag: OptionT[G, A])( + f2: Function2K[F, G, H] + ): OptionT[H, A] = + OptionT(f2(af.value, ag.value)) + override def pureK[F[_]](p: Point[F]): OptionT[F, A] = OptionT(p.point) + override val unitK: OptionT[UnitK, A] = super.unitK + override def embed[F[_]: FlatMap](ft: F[OptionT[F, A]]): OptionT[F, A] = OptionT(ft.flatMap(_.value)) + } + + private[this] def eitherTInstance[E, A]: RepresentableK[EitherT[*[_], E, A]] = + new RepresentableK[EitherT[*[_], E, A]] { + def tabulate[F[_]](hom: RepK[EitherT[*[_], E, A], *] ~> F): EitherT[F, E, A] = + EitherT(hom(RepK.mk(_.value))) + + override def mapK[F[_], G[_]](af: EitherT[F, E, A])(fk: F ~> G): EitherT[G, E, A] = af.mapK(fk) + override def productK[F[_], G[_]](af: EitherT[F, E, A], ag: EitherT[G, E, A]): EitherT[Tuple2K[F, G, *], E, A] = + EitherT(Tuple2K(af.value, ag.value)) + override def zipWith2K[F[_], G[_], H[_]](af: EitherT[F, E, A], ag: EitherT[G, E, A])(f2: Function2K[F, G, H]): EitherT[H, E, A] = + EitherT(f2(af.value, ag.value)) + override def pureK[F[_]](p: Point[F]): EitherT[F, E, A] = + EitherT(p.point) + override val unitK: EitherT[UnitK, E, A] = super.unitK + override def embed[F[_]: FlatMap](ft: F[EitherT[F, E, A]]): EitherT[F, E, A] = EitherT(ft.flatMap(_.value)) + } + + private[this] def writerTInstance[W, A]: RepresentableK[WriterT[*[_], W, A]] = + new RepresentableK[WriterT[*[_], W, A]] { + + def tabulate[F[_]](hom: RepK[WriterT[*[_], W, A], *] ~> F): WriterT[F, W, A] = WriterT(hom(RepK.mk(_.run))) + + override def mapK[F[_], G[_]](af: WriterT[F, W, A])(fk: F ~> G): WriterT[G, W, A] = af.mapK(fk) + override def productK[F[_], G[_]](af: WriterT[F, W, A], ag: WriterT[G, W, A]): WriterT[Tuple2K[F, G, *], W, A] = + WriterT(Tuple2K(af.run, ag.run)) + override def zipWith2K[F[_], G[_], H[_]](af: WriterT[F, W, A], ag: WriterT[G, W, A])(f2: Function2K[F, G, H]): WriterT[H, W, A] = + WriterT(f2(af.run, ag.run)) + override def pureK[F[_]](p: Point[F]): WriterT[F, W, A] = WriterT(p.point) + override val unitK: WriterT[UnitK, W, A] = super.unitK + override def embed[F[_]: FlatMap](ft: F[WriterT[F, W, A]]): WriterT[F, W, A] = WriterT(ft.flatMap(_.run)) + } + + private[this] def iorTInstance[E, A]: RepresentableK[IorT[*[_], E, A]] = new RepresentableK[IorT[*[_], E, A]] { + + def tabulate[F[_]](hom: RepK[IorT[*[_], E, A], *] ~> F): IorT[F, E, A] = IorT(hom(RepK.mk(_.value))) + + override def mapK[F[_], G[_]](af: IorT[F, E, A])(fk: F ~> G): IorT[G, E, A] = + af.mapK(fk) + override def productK[F[_], G[_]](af: IorT[F, E, A], ag: IorT[G, E, A]): IorT[Tuple2K[F, G, *], E, A] = + IorT(Tuple2K(af.value, ag.value)) + override def zipWith2K[F[_], G[_], H[_]](af: IorT[F, E, A], ag: IorT[G, E, A])(f2: Function2K[F, G, H]): IorT[H, E, A] = + IorT(f2(af.value, ag.value)) + override def pureK[F[_]](p: Point[F]): IorT[F, E, A] = IorT(p.point) + override val unitK: IorT[UnitK, E, A] = super.unitK + override def embed[F[_]: FlatMap](ft: F[IorT[F, E, A]]): IorT[F, E, A] = IorT(ft.flatMap(_.value)) + } + + private[this] val optionTRepresentableKAny = optionTInstance[Any] + private[this] val eitherTRepresentableKAny = eitherTInstance[Any, Any] + private[this] val writerTRepresentableKAny = writerTInstance[Any, Any] + private[this] val iorTRepresentableKAny = iorTInstance[Any, Any] + private[this] val idKRepresentableAny = idKRepresentableInst[Any] + private[this] val readerTInstanceAny = readerTInstance[Any, Any] final implicit def idKRepresentable[A]: TC[IdK[A]#λ] = idKRepresentableAny.asInstanceOf[TC[IdK[A]#λ]] + final implicit def readerTRepresentable[R, A]: TC[ReaderT[*[_], R, A]] = + readerTInstanceAny.asInstanceOf[TC[ReaderT[*[_], R, A]]] + + final implicit def optionRepresentableK[A]: TC[OptionT[*[_], A]] = + optionTRepresentableKAny.asInstanceOf[TC[OptionT[*[_], A]]] + final implicit def eitherTRepresentableK[E, A]: TC[EitherT[*[_], E, A]] = + eitherTRepresentableKAny.asInstanceOf[TC[EitherT[*[_], E, A]]] + final implicit def writerTRepresentableK[W, A]: TC[WriterT[*[_], W, A]] = + writerTRepresentableKAny.asInstanceOf[TC[WriterT[*[_], W, A]]] + final implicit def iorTRepresentableK[E, A]: TC[IorT[*[_], E, A]] = + iorTRepresentableKAny.asInstanceOf[TC[IorT[*[_], E, A]]] + } diff --git a/higherKindCore/src/main/scala/tofu/higherKind/derived/HigherKindedMacros.scala b/higherKindCore/src/main/scala/tofu/higherKind/derived/HigherKindedMacros.scala index 7a1154ddd..8fdb162ea 100644 --- a/higherKindCore/src/main/scala/tofu/higherKind/derived/HigherKindedMacros.scala +++ b/higherKindCore/src/main/scala/tofu/higherKind/derived/HigherKindedMacros.scala @@ -18,28 +18,36 @@ class HigherKindedMacros(override val c: blackbox.Context) extends cats.tagless. def tabulate(algebra: Type): (String, Type => Tree) = "tabulate" -> { - case PolyType(List(f), MethodType(List(hom), _)) => - val members = overridableMembersOf(algebra) - val types = delegateAbstractTypes(algebra, members, algebra) + case PolyType(List(f), MethodType(List(hom), af)) => + + val members = overridableMembersOf(af) + val types = delegateAbstractTypes(af, members, af) val repk = reify(tofu.higherKind.RepK).tree + val funk = reify(tofu.syntax.functionK).tree val alg = TermName(c.freshName("alg")) + val rep = TermName(c.freshName("rep")) val et = tq"" val algv = q"val $alg: $et" - val ff = algebra match { - case PolyType(List(ff1), _) => ff1 - } - val methods = delegateMethods(algebra, members, NoSymbol) { - case method if method.occursInParams(ff) => - abort(s"Type parameter $ff appears in contravariant position in method ${method.name}") + val repv = q"val $rep: $et" - case method if method.occursInReturn(ff) => + val methods = delegateMethods(af, members, NoSymbol) { + case method if method.occursInParams(f) => + abort(s"Type parameter $f appears in contravariant position in method ${method.name}") + + case method if method.returnType.typeConstructor.typeSymbol == f => val params = method.paramLists.map(_.map(_.name)) val body = q"$hom($repk[$algebra](($algv => $alg.${method.name}(...$params))))" - val tpe = appliedType(f, method.returnType.typeArgs) - method.copy(body = body, returnType = tpe) + method.copy(body = body) + + case method if method.occursInReturn(f) => + val params = method.paramLists.map(_.map(_.name)) + val tt = polyType(f :: Nil, method.returnType) + val F = summon[RepresentableK[Any]](tt) + val body = q"$F.tabulate($funk.funK($repv => $hom($repk[$algebra]($algv => $rep($alg.${method.name}(...$params))))))" + method.copy(body = body) case method => - abort(s"Type parameter $ff does not appear in return in method ${method.name}") + abort(s"Type parameter $f does not appear in return in method ${method.name}") } val res = implement(algebra)(f)(types ++ methods) From f9279eec593c84cd90dffb6eb4f97a9e7bd21f37 Mon Sep 17 00:00:00 2001 From: Oleg Nizhnik Date: Tue, 11 Feb 2020 16:30:20 +0300 Subject: [PATCH 2/3] clean test --- .../derived/RepresentableKSuite.scala | 45 ++++++++----------- .../derived/HigherKindedMacros.scala | 2 +- 2 files changed, 20 insertions(+), 27 deletions(-) diff --git a/derivation/src/test/scala/tofu/higherKind/derived/RepresentableKSuite.scala b/derivation/src/test/scala/tofu/higherKind/derived/RepresentableKSuite.scala index a87aab061..8b5e9cb18 100644 --- a/derivation/src/test/scala/tofu/higherKind/derived/RepresentableKSuite.scala +++ b/derivation/src/test/scala/tofu/higherKind/derived/RepresentableKSuite.scala @@ -3,15 +3,17 @@ package tofu.higherKind.derived import RepresentableKSuite.Foo import cats.data.{OptionT, Tuple2K} import cats.instances.either._ +import cats.instances.option._ import cats.syntax.either._ import cats.syntax.functor._ +import cats.syntax.traverse._ +import cats.syntax.option._ import cats.tagless.syntax.functorK._ import cats.tagless.syntax.semigroupalK._ import cats.{Id, ~>} import derevo.derive import org.scalatest.{FlatSpec, Matchers} import tofu.data.Embedded -import tofu.higherKind.{RepK, RepresentableK} import tofu.syntax.embed._ import tofu.syntax.functionK.funK @@ -23,32 +25,38 @@ class RepresentableKSuite extends FlatSpec with Matchers { Try(s.toDouble).toEither.left.map(_ => s"could not parse $s as double").map(_ * x) override def bar(a: List[Int]): Either[String, Unit] = a.headOption.toRight("must contain at least one element").void - def baz(a: List[Int]): OptionT[Either[String, *], Unit] = OptionT.liftF(Left("hello")) + def baz(a: List[String]): OptionT[Either[String, *], Unit] = + OptionT(a.headOption.traverse(_.asLeft[Unit])) } val defaultFoo: Foo[Id] = new Foo[Id] { override def foo(x: Int, s: String): Double = x.toDouble override def bar(a: List[Int]): Unit = () - def baz(a: List[Int]): OptionT[Id, Unit] = OptionT.none + def baz(a: List[String]): OptionT[Id, Unit] = OptionT.none } + type MapR[+A] = Embedded[(String, +*), List, A] + "representableK" should "generate nice mapK" in { - val eitherToList: Either[String, *] ~> Embedded[(String, +*), List, *] = funK { + val eitherToList: Either[String, *] ~> MapR = funK { case Left(err) => Embedded(((err, Nil))) case Right(res) => Embedded((("", List(res)))) } - val mappedFoo = checkingFoo.mapK(eitherToList) + val mappedFoo: Foo[MapR] = checkingFoo.mapK(eitherToList) mappedFoo.foo(2, "2.3") should ===(Embedded(("", List(4.6)))) mappedFoo.foo(2, "fail") should ===(Embedded(("could not parse fail as double", List()))) mappedFoo.bar(List(4, 5, 6)) should ===(Embedded(("", List(())))) mappedFoo.bar(List()) should ===(Embedded(("must contain at least one element", List()))) + + mappedFoo.baz(List("one", "two")) should ===(OptionT[MapR, Unit](Embedded(("one", Nil)))) + mappedFoo.baz(Nil) should ===(OptionT[MapR, Unit](Embedded(("", List(None))))) } "representableK" should "generate nice productK" in { - val zippedFoo = checkingFoo.productK(defaultFoo) + val zippedFoo: Foo[Tuple2K[Either[String, *], Id, *]] = checkingFoo.productK(defaultFoo) def tuple[A](e: Either[String, A], a: A) = Tuple2K[Either[String, *], Id, A](e, a) @@ -57,6 +65,10 @@ class RepresentableKSuite extends FlatSpec with Matchers { zippedFoo.bar(List(4, 5, 6)) should ===(tuple(Right(()), ())) zippedFoo.bar(List()) should ===(tuple(Left("must contain at least one element"), ())) + + zippedFoo.baz(List("one", "two")) should ===(OptionT(tuple(Left("one"), none[Unit]))) + zippedFoo.baz(Nil) should ===(OptionT(tuple(Right(none[Unit]), none[Unit]))) + } "representableK" should "generate nice embed" in { @@ -85,25 +97,6 @@ object RepresentableKSuite { def bar(a: List[Int]): F[Unit] - def baz(a: List[Int]): OptionT[F, Unit] - } - - trait Foo1[F[_]] { - def foo(x: Int, s: String): F[Double] - - def bar(a: List[Int]): F[Unit] - - def baz(a: List[Int]): OptionT[F, Unit] - } - - new RepresentableK[Foo1] { - def tabulate[F[_]](hom: RepK[Foo1, *] ~> F): Foo1[F] = new Foo1[F] { - def foo(x: Int, s: String): F[Double] = hom(RepK.mk(_.foo(x, s))) - def bar(a: List[Int]): F[Unit] = hom(RepK.mk(_.bar(a))) - def baz(a: List[Int]): OptionT[F, Unit] = { - val OT = RepresentableK[OptionT[*[_], Unit]] - OT.tabulate[F](funK(rep => hom(RepK[Foo1](foo => rep(foo.baz(a)))))) - } - } + def baz(a: List[String]): OptionT[F, Unit] } } diff --git a/higherKindCore/src/main/scala/tofu/higherKind/derived/HigherKindedMacros.scala b/higherKindCore/src/main/scala/tofu/higherKind/derived/HigherKindedMacros.scala index 8fdb162ea..1565faa59 100644 --- a/higherKindCore/src/main/scala/tofu/higherKind/derived/HigherKindedMacros.scala +++ b/higherKindCore/src/main/scala/tofu/higherKind/derived/HigherKindedMacros.scala @@ -87,7 +87,7 @@ class HigherKindedMacros(override val c: blackbox.Context) extends cats.tagless. } def representableK[Alg[_[_]]](implicit tag: WeakTypeTag[Alg[Any]]): Tree = - instantiate[RepresentableK[Alg]](tag)(tabulate, productK, mapK) + instantiate[RepresentableK[Alg]](tag)(tabulate, productK, mapK, embedf) def embed[Alg[_[_]]](implicit tag: WeakTypeTag[Alg[Any]]): Tree = instantiate[Embed[Alg]](tag)(embedf) From 9a7482c617b0638702e348287019dc00d754d657 Mon Sep 17 00:00:00 2001 From: Oleg Nizhnik Date: Tue, 11 Feb 2020 17:05:43 +0300 Subject: [PATCH 3/3] formatting --- .../main/scala/tofu/higherKind/Embed.scala | 9 ++------ .../tofu/higherKind/RepresentableK.scala | 22 ++++++++++++------- .../derived/HigherKindedMacros.scala | 8 +++---- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/higherKindCore/src/main/scala/tofu/higherKind/Embed.scala b/higherKindCore/src/main/scala/tofu/higherKind/Embed.scala index 74e4aa394..9ac5f4045 100644 --- a/higherKindCore/src/main/scala/tofu/higherKind/Embed.scala +++ b/higherKindCore/src/main/scala/tofu/higherKind/Embed.scala @@ -17,13 +17,8 @@ trait EmbedInstanceChain[TC[u[_[_]]] >: Embed[u]] extends RepresentableKInstance def embed[F[_]: FlatMap](ft: F[Free[F, A]]): Free[F, A] = Free.roll(ft) } + private[this] val freeEmbedAny = freeInstance[Any] - - - private[this] val freeEmbedAny = freeInstance[Any] - - - - final implicit def freeEmbed[A]: TC[Free[*[_], A]] = freeEmbedAny.asInstanceOf[TC[Free[*[_], A]]] + final implicit def freeEmbed[A]: TC[Free[*[_], A]] = freeEmbedAny.asInstanceOf[TC[Free[*[_], A]]] } diff --git a/higherKindCore/src/main/scala/tofu/higherKind/RepresentableK.scala b/higherKindCore/src/main/scala/tofu/higherKind/RepresentableK.scala index ba5dd1331..62bea0869 100644 --- a/higherKindCore/src/main/scala/tofu/higherKind/RepresentableK.scala +++ b/higherKindCore/src/main/scala/tofu/higherKind/RepresentableK.scala @@ -100,11 +100,13 @@ trait RepresentableKInstanceChain[TC[u[_[_]]] >: RepresentableK[u]] { override def mapK[F[_], G[_]](af: EitherT[F, E, A])(fk: F ~> G): EitherT[G, E, A] = af.mapK(fk) override def productK[F[_], G[_]](af: EitherT[F, E, A], ag: EitherT[G, E, A]): EitherT[Tuple2K[F, G, *], E, A] = EitherT(Tuple2K(af.value, ag.value)) - override def zipWith2K[F[_], G[_], H[_]](af: EitherT[F, E, A], ag: EitherT[G, E, A])(f2: Function2K[F, G, H]): EitherT[H, E, A] = + override def zipWith2K[F[_], G[_], H[_]](af: EitherT[F, E, A], ag: EitherT[G, E, A])( + f2: Function2K[F, G, H] + ): EitherT[H, E, A] = EitherT(f2(af.value, ag.value)) override def pureK[F[_]](p: Point[F]): EitherT[F, E, A] = EitherT(p.point) - override val unitK: EitherT[UnitK, E, A] = super.unitK + override val unitK: EitherT[UnitK, E, A] = super.unitK override def embed[F[_]: FlatMap](ft: F[EitherT[F, E, A]]): EitherT[F, E, A] = EitherT(ft.flatMap(_.value)) } @@ -116,10 +118,12 @@ trait RepresentableKInstanceChain[TC[u[_[_]]] >: RepresentableK[u]] { override def mapK[F[_], G[_]](af: WriterT[F, W, A])(fk: F ~> G): WriterT[G, W, A] = af.mapK(fk) override def productK[F[_], G[_]](af: WriterT[F, W, A], ag: WriterT[G, W, A]): WriterT[Tuple2K[F, G, *], W, A] = WriterT(Tuple2K(af.run, ag.run)) - override def zipWith2K[F[_], G[_], H[_]](af: WriterT[F, W, A], ag: WriterT[G, W, A])(f2: Function2K[F, G, H]): WriterT[H, W, A] = + override def zipWith2K[F[_], G[_], H[_]](af: WriterT[F, W, A], ag: WriterT[G, W, A])( + f2: Function2K[F, G, H] + ): WriterT[H, W, A] = WriterT(f2(af.run, ag.run)) - override def pureK[F[_]](p: Point[F]): WriterT[F, W, A] = WriterT(p.point) - override val unitK: WriterT[UnitK, W, A] = super.unitK + override def pureK[F[_]](p: Point[F]): WriterT[F, W, A] = WriterT(p.point) + override val unitK: WriterT[UnitK, W, A] = super.unitK override def embed[F[_]: FlatMap](ft: F[WriterT[F, W, A]]): WriterT[F, W, A] = WriterT(ft.flatMap(_.run)) } @@ -131,10 +135,12 @@ trait RepresentableKInstanceChain[TC[u[_[_]]] >: RepresentableK[u]] { af.mapK(fk) override def productK[F[_], G[_]](af: IorT[F, E, A], ag: IorT[G, E, A]): IorT[Tuple2K[F, G, *], E, A] = IorT(Tuple2K(af.value, ag.value)) - override def zipWith2K[F[_], G[_], H[_]](af: IorT[F, E, A], ag: IorT[G, E, A])(f2: Function2K[F, G, H]): IorT[H, E, A] = + override def zipWith2K[F[_], G[_], H[_]](af: IorT[F, E, A], ag: IorT[G, E, A])( + f2: Function2K[F, G, H] + ): IorT[H, E, A] = IorT(f2(af.value, ag.value)) - override def pureK[F[_]](p: Point[F]): IorT[F, E, A] = IorT(p.point) - override val unitK: IorT[UnitK, E, A] = super.unitK + override def pureK[F[_]](p: Point[F]): IorT[F, E, A] = IorT(p.point) + override val unitK: IorT[UnitK, E, A] = super.unitK override def embed[F[_]: FlatMap](ft: F[IorT[F, E, A]]): IorT[F, E, A] = IorT(ft.flatMap(_.value)) } diff --git a/higherKindCore/src/main/scala/tofu/higherKind/derived/HigherKindedMacros.scala b/higherKindCore/src/main/scala/tofu/higherKind/derived/HigherKindedMacros.scala index 1565faa59..a1f1e2cb7 100644 --- a/higherKindCore/src/main/scala/tofu/higherKind/derived/HigherKindedMacros.scala +++ b/higherKindCore/src/main/scala/tofu/higherKind/derived/HigherKindedMacros.scala @@ -19,7 +19,6 @@ class HigherKindedMacros(override val c: blackbox.Context) extends cats.tagless. def tabulate(algebra: Type): (String, Type => Tree) = "tabulate" -> { case PolyType(List(f), MethodType(List(hom), af)) => - val members = overridableMembersOf(af) val types = delegateAbstractTypes(af, members, af) val repk = reify(tofu.higherKind.RepK).tree @@ -41,9 +40,10 @@ class HigherKindedMacros(override val c: blackbox.Context) extends cats.tagless. case method if method.occursInReturn(f) => val params = method.paramLists.map(_.map(_.name)) - val tt = polyType(f :: Nil, method.returnType) - val F = summon[RepresentableK[Any]](tt) - val body = q"$F.tabulate($funk.funK($repv => $hom($repk[$algebra]($algv => $rep($alg.${method.name}(...$params))))))" + val tt = polyType(f :: Nil, method.returnType) + val F = summon[RepresentableK[Any]](tt) + val body = + q"$F.tabulate($funk.funK($repv => $hom($repk[$algebra]($algv => $rep($alg.${method.name}(...$params))))))" method.copy(body = body) case method =>