Skip to content
Closed
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
43 changes: 34 additions & 9 deletions core/src/main/scala-3/cats/derived/empty.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,47 @@ trait DerivedEmpty[A] extends Empty[A]:
protected def emptyValue(): A
lazy val empty: A = emptyValue()

enum EmptyOrDerived[A]:
case L(empty: Empty[A])
case R(derived: DerivedEmpty[A])

object EmptyOrDerived:
inline given [A]: EmptyOrDerived[A] = summonFrom {
case e: Empty[A] => L(e)
case d: DerivedEmpty[A] => R(d)
}

object DerivedEmpty:
inline given [A]: DerivedEmpty[A] = summonFrom {
case given Empty[A] => delegated
case given K0.ProductInstances[DerivedEmpty, A] => product
case given K0.ProductInstances[EmptyOrDerived, A] => product
case given K0.CoproductGeneric[A] => coproduct
}

def delegated[A](using A: => Empty[A]): DerivedEmpty[A] =
() => A.empty

def product[A](using inst: K0.ProductInstances[DerivedEmpty, A]): DerivedEmpty[A] =
() => inst.construct([A] => (A: DerivedEmpty[A]) => A.empty)
def product[A](using inst: K0.ProductInstances[EmptyOrDerived, A]): DerivedEmpty[A] =
() => inst.construct([A] => (A: EmptyOrDerived[A]) =>
A match {
case EmptyOrDerived.L(e) => e.empty
case EmptyOrDerived.R(d) => d.empty
})

inline def coproduct[A](using gen: K0.CoproductGeneric[A]): DerivedEmpty[A] =
K0.summonFirst[DerivedEmpty, gen.MirroredElemTypes, A]
K0.summonFirst[EmptyOrDerived, gen.MirroredElemTypes, A] match {
case EmptyOrDerived.L(e) => () => e.empty
case EmptyOrDerived.R(d) => d
}

trait EmptyDerivation:
extension (E: Empty.type)
def derived[A](using instance: DerivedEmpty[A]): Empty[A] = instance
def derived[A](using instance: DerivedEmpty[A]): Empty[A] =
Empty(instance.empty)


import empty.derived

case class Foo(i: Int, b: IntTree) derives Empty
enum IntTree:
case Leaf
case Node(left: IntTree, value: Int, right: IntTree)

@main def test =
println(Empty[Foo].empty)