From 409db1674ec4ac4c8b36f7f9a850d7cd6981885e Mon Sep 17 00:00:00 2001 From: Georgi Krastev Date: Wed, 10 Jan 2024 09:26:38 +0200 Subject: [PATCH] Fix FunctorK test example for recursive types Make instances in `functorKGen` by-name. --- .../test/scala/shapeless3/deriving/adts.scala | 17 +++- .../scala/shapeless3/deriving/deriving.scala | 80 ++++++++++--------- .../shapeless3/deriving/type-classes.scala | 49 ++++++------ 3 files changed, 78 insertions(+), 68 deletions(-) diff --git a/modules/deriving/src/test/scala/shapeless3/deriving/adts.scala b/modules/deriving/src/test/scala/shapeless3/deriving/adts.scala index 6e16ccc..9f22b98 100644 --- a/modules/deriving/src/test/scala/shapeless3/deriving/adts.scala +++ b/modules/deriving/src/test/scala/shapeless3/deriving/adts.scala @@ -21,7 +21,7 @@ package shapeless3.deriving object adts: case class ISB(i: Int, s: String, b: Boolean) derives Monoid, Eq, Empty, Show, Read - case class Box[A](x: A) derives Monoid, Eq, Show, Read, Functor, Pure, Ord, Traverse, Foldable + case class Box[A](x: A) derives Monoid, Eq, Show, Read, Functor, Return, Ord, Traverse, Foldable case class Recursive(h: Int, t: Option[Recursive]) derives Monoid @@ -29,7 +29,7 @@ object adts: case object NoneInt extends OptionInt case class SomeInt(value: Int) extends OptionInt - sealed trait Opt[+A] derives Eq, Show, Read, Functor, EmptyK, Pure, Ord, Traverse, Foldable + sealed trait Opt[+A] derives Eq, Show, Read, Functor, EmptyK, Return, Ord, Traverse, Foldable case object Nn extends Opt[Nothing] case class Sm[+A](value: A) extends Opt[A] @@ -53,8 +53,13 @@ object adts: def fold: T = this match case Given(t) => t case Default(t) => t + def toOption: Option[T] = this match + case Given(t) => Some(t) + case Default(_) => None + object OptionD: - val fold: OptionD ~> Id = [t] => (ot: OptionD[t]) => ot.fold + val fold: OptionD ~> Id = [t] => (od: OptionD[t]) => od.fold + val toOption: OptionD ~> Option = [t] => (od: OptionD[t]) => od.toOption case class Given[T](value: T) extends OptionD[T] case class Default[T](value: T) extends OptionD[T] @@ -78,3 +83,9 @@ object adts: case Top(head: A, tail: Zipper[A]) case Bot(init: Zipper[A], last: A) case Focus(left: List[A], focus: ::[A], right: List[A]) + + sealed trait HkNel[F[_]] + case class HkCons[F[_]](head: F[Int], tail: HkNel[F]) extends HkNel[F] + case class HkOne[F[_]](head: F[Int]) extends HkNel[F] + +end adts diff --git a/modules/deriving/src/test/scala/shapeless3/deriving/deriving.scala b/modules/deriving/src/test/scala/shapeless3/deriving/deriving.scala index bb10daa..efe0044 100644 --- a/modules/deriving/src/test/scala/shapeless3/deriving/deriving.scala +++ b/modules/deriving/src/test/scala/shapeless3/deriving/deriving.scala @@ -41,7 +41,7 @@ object Inc: class DerivationTests: @Test - def monoid: Unit = + def monoid(): Unit = val v0 = Monoid[ISB] assert(v0.empty == ISB(0, "", false)) assert(v0.combine(ISB(1, "foo", false), ISB(2, "bar", true)) == ISB(3, "foobar", true)) @@ -60,7 +60,7 @@ class DerivationTests: ) @Test - def eq: Unit = + def eq(): Unit = val v0 = Eq[SomeInt] assert(v0.eqv(SomeInt(23), SomeInt(23))) assert(!v0.eqv(SomeInt(23), SomeInt(13))) @@ -96,7 +96,7 @@ class DerivationTests: assert(!v9.eqv(SmE(23), NnE)) @Test - def order: Unit = + def order(): Unit = val v0 = Ord[Unit] assert(v0.compare((), ()) == 0) @@ -143,7 +143,7 @@ class DerivationTests: assert(v8.compare(SmE("foo"), NnE) == 1) @Test - def functor: Unit = + def functor(): Unit = val v0 = Functor[Box] assert(v0.map(Box("foo"))(_.length) == Box(3)) @@ -181,7 +181,7 @@ class DerivationTests: loop(n, CNil) @Test - def foldable: Unit = + def foldable(): Unit = val v0 = Foldable[Box] assert(v0.foldLeft(Box(1))(0)((acc: Int, x: Int) => acc + x) == 1) assert(v0.foldRight(Box(1))(Eval.now(0))((x: Int, acc: Eval[Int]) => acc.map(_ + x)).value == 1) @@ -218,7 +218,7 @@ class DerivationTests: assert(v7.foldRight(NnE)(Eval.now(0))((x: Int, acc: Eval[Int]) => acc.map(_ + x)).value == 0) @Test - def traverse: Unit = + def traverse(): Unit = val v0 = Traverse[Box] assert(v0.traverse(Box(1))((x: Int) => List(x + 1)) == List(Box(2))) @@ -231,12 +231,12 @@ class DerivationTests: assert(v3.traverse(Nn)((x: Int) => List(x + 1)) == List(Nn)) val v4 = Traverse[Const[CNil.type]] - assert(v4.traverse(CNil)(Option.apply) == Some(CNil)) + assert(v4.traverse(CNil)(Option.apply).contains(CNil)) val v5 = Traverse[CCons] - assert(v5.traverse(CList("foo", "bar"))(Option.apply) == Some(CList("foo", "bar"))) + assert(v5.traverse(CList("foo", "bar"))(Option.apply).contains(CList("foo", "bar"))) val v6 = Traverse[CList] - assert(v6.traverse(CList("foo", "bar"))(Option.apply) == Some(CList("foo", "bar"))) - assert(v6.traverse(CNil)(Option.apply) == Some(CNil)) + assert(v6.traverse(CList("foo", "bar"))(Option.apply).contains(CList("foo", "bar"))) + assert(v6.traverse(CNil)(Option.apply).contains(CNil)) assert(v6.traverse(CList("foo", "bar"))(() => _).apply() == CList("foo", "bar")) assert(v6.traverse(CList(1, 2))(x => List(x, x + 1)) == List(CList(1, 2), CList(1, 3), CList(2, 2), CList(2, 3))) @@ -245,15 +245,18 @@ class DerivationTests: assert(v7.traverse(NnE)((x: Int) => List(x + 1)) == List(NnE)) val v8 = Traverse[Phantom] - assert(v8.traverse(Phantom())(Option.apply) == Some(Phantom())) + assert(v8.traverse(Phantom())(Option.apply).contains(Phantom())) @Test - def functork: Unit = + def functorK(): Unit = val v0 = FunctorK[Order] assert(v0.mapK(Order[OptionD](Given("Epoisse"), Default(10)))(OptionD.fold) == Order[Id]("Epoisse", 10)) + val arg1 = HkCons(Given(42), HkCons(Default(0), HkOne(Given(313)))) + val exp1 = HkCons(Some(42), HkCons(None, HkOne(Some(313)))) + assert(FunctorK[HkNel].mapK(arg1)(OptionD.toOption) == exp1) @Test - def bifunctor: Unit = + def bifunctor(): Unit = val v0 = Bifunctor[ConsF] val v1 = Bifunctor[ListF] val v2: ListF.List[String] = Fix(ConsF("foo", Fix(ConsF("quux", Fix(ConsF("wibble", Fix(NilF))))))) @@ -261,7 +264,7 @@ class DerivationTests: assert(Bifunctor.map((_: String).length)(v2) == v3) @Test - def data: Unit = + def data(): Unit = val v0 = Data[Size.type, ISB, Int] assert(v0.gmapQ(ISB(23, "foo", true)).sum == 27) val v1 = Data[Size.type, OptionInt, Int] @@ -271,7 +274,7 @@ class DerivationTests: assert(v2.gmapQ(CCons("foo", CCons("quux", CCons("wibble", CNil)))).sum == 13) @Test - def datat: Unit = + def dataT(): Unit = val v0 = DataT[Inc.type, ISB] assert(v0.gmapT(ISB(23, "foo", true)) == ISB(24, "foo!", false)) val v1 = DataT[Inc.type, OptionInt] @@ -281,32 +284,32 @@ class DerivationTests: assert(v2.gmapT(CCons(1, CCons(2, CCons(3, CNil)))) == CCons(2, CCons(3, CCons(4, CNil)))) @Test - def empty: Unit = + def empty(): Unit = val v0 = Empty[ISB] assert(v0.empty == ISB(0, "", false)) @Test - def emptyk: Unit = + def emptyK(): Unit = val v0 = EmptyK[Opt] assert(v0.empty[Int] == Nn) val v1 = EmptyK[CList] assert(v1.empty[Int] == CNil) @Test - def pure: Unit = - val v0 = Pure[Box] + def pure(): Unit = + val v0 = Return[Box] assert(v0.pure(23) == Box(23)) - val v1 = Pure[CList] + val v1 = Return[CList] assert(v1.pure(23) == CCons(23, CNil)) @Test - def labels: Unit = + def labels(): Unit = val v0 = K0.Generic[ISB] val v1 = constValueTuple[v0.MirroredElemLabels] assert(v1 == ("i", "s", "b")) @Test - def show: Unit = + def show(): Unit = val v0 = Show[ISB] assert(v0.show(ISB(23, "foo", true)) == """ISB(i: 23, s: "foo", b: true)""") @@ -323,7 +326,7 @@ class DerivationTests: val v4 = Show[CList[Int]] assert( - v4.show((CCons(1, CCons(2, CCons(3, CNil))))) == "CCons(hd: 1, tl: CCons(hd: 2, tl: CCons(hd: 3, tl: CNil)))" + v4.show(CCons(1, CCons(2, CCons(3, CNil)))) == "CCons(hd: 1, tl: CCons(hd: 2, tl: CCons(hd: 3, tl: CNil)))" ) val v5 = Show[Order[Id]] @@ -334,42 +337,41 @@ class DerivationTests: assert(v6.show(NnE) == "NnE") @Test - def read: Unit = + def read(): Unit = val v0 = Read[ISB] - assert(v0.read("""ISB(i: 23, s: "foo", b: true)""") == Some((ISB(23, "foo", true), ""))) + assert(v0.read("""ISB(i: 23, s: "foo", b: true)""").contains((ISB(23, "foo", true), ""))) val v1 = Read[OptionInt] - assert(v1.read("SomeInt(value: 23)") == Some((SomeInt(23), ""))) - assert(v1.read("NoneInt") == Some((NoneInt, ""))) + assert(v1.read("SomeInt(value: 23)").contains((SomeInt(23), ""))) + assert(v1.read("NoneInt").contains((NoneInt, ""))) val v2 = Read[Box[Int]] - assert(v2.read("Box(x: 23)") == Some((Box(23), ""))) + assert(v2.read("Box(x: 23)").contains((Box(23), ""))) val v3 = Read[Opt[Int]] - assert(v3.read("Sm(value: 23)") == Some((Sm(23), ""))) - assert(v3.read("Nn") == Some((Nn, ""))) + assert(v3.read("Sm(value: 23)").contains((Sm(23), ""))) + assert(v3.read("Nn").contains((Nn, ""))) val v4 = Read[CList[Int]] assert( - v4.read("CCons(hd: 1, tl: CCons(hd: 2, tl: CCons(hd: 3, tl: CNil)))") == Some( - (CCons(1, CCons(2, CCons(3, CNil))), "") - ) + v4.read("CCons(hd: 1, tl: CCons(hd: 2, tl: CCons(hd: 3, tl: CNil)))") + .contains((CCons(1, CCons(2, CCons(3, CNil))), "")) ) val v5 = Read[Order[Id]] - assert(v5.read("""Order(item: "Epoisse", quantity: 10)""") == Some((Order[Id]("Epoisse", 10), ""))) + assert(v5.read("""Order(item: "Epoisse", quantity: 10)""").contains((Order[Id]("Epoisse", 10), ""))) val v6 = Read[OptE[Int]] - assert(v6.read("SmE(value: 23)") == Some((SmE(23), ""))) - assert(v6.read("NnE") == Some((NnE, ""))) + assert(v6.read("SmE(value: 23)").contains((SmE(23), ""))) + assert(v6.read("NnE").contains((NnE, ""))) @Test - def transform: Unit = + def transform(): Unit = val v0 = Transform[BI, ISB] assert(v0(BI(true, 23)) == ISB(23, "", true)) @Test - def repr: Unit = + def repr(): Unit = val v0 = K0.ProductGeneric[Box[Int]] val v1 = v0.toRepr(Box(23)) val v1a: Tuple1[Int] = v1 @@ -381,7 +383,7 @@ class DerivationTests: assert(v3 == ("Epoisse", 10)) @Test - def parsing: Unit = + def parsing(): Unit = val parser = Parser[ISB] // Applicative assertEquals(Right(ISB(42, "foo", true)), parser.parseAccum("s=foo,i=42,b=true,hidden=?")) diff --git a/modules/deriving/src/test/scala/shapeless3/deriving/type-classes.scala b/modules/deriving/src/test/scala/shapeless3/deriving/type-classes.scala index 3de9aaa..dd4b067 100644 --- a/modules/deriving/src/test/scala/shapeless3/deriving/type-classes.scala +++ b/modules/deriving/src/test/scala/shapeless3/deriving/type-classes.scala @@ -250,7 +250,7 @@ object Optional: def headOption[A](fa: Option[A]): Option[A] = fa given [T]: Optional[Const[T]] with def headOption[A](fa: T): Option[A] = None - given NonEmpty[::] with + given cons: NonEmpty[::] with def head[A](fa: ::[A]): A = fa.head given NonEmpty[Some] with def head[A](fa: Some[A]): A = fa.get @@ -333,7 +333,7 @@ object FunctorK: given [T]: FunctorK[K11.Id[T]] with def mapK[A[_], B[_]](at: A[T])(f: A ~> B): B[T] = f(at) - given functorKGen[H[_[_]]](using inst: K11.Instances[FunctorK, H]): FunctorK[H] with + given functorKGen[H[_[_]]](using inst: => K11.Instances[FunctorK, H]): FunctorK[H] with def mapK[A[_], B[_]](ha: H[A])(f: A ~> B): H[B] = inst.map(ha)([t[_[_]]] => (ft: FunctorK[t], ta: t[A]) => ft.mapK(ta)(f)) @@ -458,10 +458,10 @@ object Empty: given Empty[Boolean] = mkEmpty(false) given emptyGen[A](using inst: K0.ProductInstances[Empty, A]): Empty[A] = - mkEmpty(inst.construct([a] => (_: Empty[a]).empty)) + mkEmpty(inst.construct([a] => (A: Empty[a]) => A.empty)) inline given emptyGenC[A](using gen: K0.CoproductGeneric[A]): Empty[A] = - mkEmpty(gen.withOnly[Empty, A]([a <: A] => (_: Empty[a]).empty)) + mkEmpty(gen.withOnly[Empty, A]([a <: A] => (A: Empty[a]) => A.empty)) inline def derived[A](using gen: K0.Generic[A]): Empty[A] = inline gen match @@ -481,11 +481,11 @@ object EmptyK: new EmptyK[F]: def empty[A] = f[A]() - given emptyKGen[A[_]](using inst: K1.ProductInstances[EmptyK, A]): EmptyK[A] = - mkEmptyK([t] => () => inst.construct([f[_]] => (_: EmptyK[f]).empty[t])) + given emptyKGen[F[_]](using inst: K1.ProductInstances[EmptyK, F]): EmptyK[F] = + mkEmptyK([t] => () => inst.construct([f[_]] => (F: EmptyK[f]) => F.empty[t])) - inline given emptyKGenC[A[_]](using gen: K1.CoproductGeneric[A]): EmptyK[A] = - mkEmptyK[A]([t] => () => gen.withOnly[EmptyK, A[t]]([a[x] <: A[x]] => (_: EmptyK[a]).empty[t])) + inline given emptyKGenC[F[_]](using gen: K1.CoproductGeneric[F]): EmptyK[F] = + mkEmptyK[F]([t] => () => gen.withOnly[EmptyK, F[t]]([f[x] <: F[x]] => (F: EmptyK[f]) => F.empty[t])) inline def derived[A[_]](using gen: K1.Generic[A]): EmptyK[A] = inline gen match @@ -509,30 +509,27 @@ object Alt1: case gt: G[T] => new Alt1G(gt) } -trait Pure[F[_]]: +trait Return[F[_]]: def pure[A](a: A): F[A] -object Pure: - def apply[F[_]](using ef: Pure[F]): Pure[F] = ef +object Return: + def apply[F[_]](using F: Return[F]): Return[F] = F - def mkPure[F[_]](f: [a] => a => F[a]): Pure[F] = - new Pure[F]: - def pure[A](a: A) = f(a) + def from[F[_]](f: [a] => a => F[a]): Return[F] = new Return[F]: + def pure[A](a: A) = f(a) - given Pure[Id] = mkPure([T] => (t: T) => t) + given Return[Id] = + from([T] => (t: T) => t) - given pureGen[A[_]](using inst: K1.ProductInstances[Alt1.Of[Pure, EmptyK], A]): Pure[A] = - mkPure[A]( - [t] => (a: t) => inst.construct([f[_]] => (af: Alt1.Of[Pure, EmptyK][f]) => af.fold[f[t]](_.pure(a))(_.empty[t])) - ) + given pureGen[A[_]](using inst: K1.ProductInstances[Alt1.Of[Return, EmptyK], A]): Return[A] = from[A]: + [t] => (a: t) => inst.construct([f[_]] => (af: Alt1.Of[Return, EmptyK][f]) => af.fold[f[t]](_.pure(a))(_.empty[t])) - inline given pureGenC[A[_]](using gen: K1.CoproductGeneric[A]): Pure[A] = - mkPure[A]([t] => (a: t) => gen.withFirst[Pure, A[t]]([f[x] <: A[x]] => (_: Pure[f]).pure(a))) + inline given pureGenC[F[_]](using gen: K1.CoproductGeneric[F]): Return[F] = from[F]: + [t] => (a: t) => gen.withFirst[Return, F[t]]([f[x] <: F[x]] => (F: Return[f]) => F.pure(a)) - inline def derived[A[_]](using gen: K1.Generic[A]): Pure[A] = - inline gen match - case given K1.ProductGeneric[A] => pureGen - case given K1.CoproductGeneric[A] => pureGenC + inline def derived[A[_]](using gen: K1.Generic[A]): Return[A] = inline gen match + case given K1.ProductGeneric[A] => pureGen + case given K1.CoproductGeneric[A] => pureGenC trait Show[T]: def show(t: T): String @@ -587,7 +584,7 @@ object Read: yield (p, tl) given Read[Int] = readPrimitive("""(-?\d*)(.*)""".r, s => Try(s.toInt).toOption) - given Read[String] = (s: String) => head(s, """\"(.*)\"(.*)""".r) + given Read[String] = (s: String) => head(s, """"(.*)"(.*)""".r) given Read[Boolean] = readPrimitive("""(true|false)(.*)""".r, s => Try(s.toBoolean).toOption) given readGen[T](using inst: K0.ProductInstances[Read, T], labelling: Labelling[T]): Read[T] with