Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix FunctorK test example for recursive types #194

Merged
merged 1 commit into from
Jan 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions modules/deriving/src/test/scala/shapeless3/deriving/adts.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ 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

sealed trait OptionInt derives Eq, Show, Read, Ord
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]

Expand All @@ -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]
Expand All @@ -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
80 changes: 41 additions & 39 deletions modules/deriving/src/test/scala/shapeless3/deriving/deriving.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand All @@ -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)))
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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))

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)))

Expand All @@ -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)))

Expand All @@ -245,23 +245,26 @@ 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)))))))
val v3: ListF.List[Int] = Fix(ConsF(3, Fix(ConsF(4, Fix(ConsF(6, Fix(NilF)))))))
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]
Expand All @@ -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]
Expand All @@ -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)""")

Expand All @@ -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]]
Expand All @@ -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
Expand All @@ -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=?"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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))

Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down