Skip to content

Commit

Permalink
Deep and Coproduct Empty derivation
Browse files Browse the repository at this point in the history
It looks like we will need `OrElse` again.
  • Loading branch information
joroKr21 committed Jun 1, 2021
1 parent a033a34 commit 8a49e4e
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 6 deletions.
24 changes: 18 additions & 6 deletions core/src/main/scala-3/cats/derived/empty.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,24 @@ import shapeless3.deriving.K0

object empty extends EmptyDerivation

class ProductEmpty[F[x] <: Empty[x], A](
using inst: K0.ProductInstances[F, A]
) extends Empty[A]:
val empty: A = inst.construct([A] => (F: F[A]) => F.empty)
trait DerivedEmpty[A] extends Empty[A]:
protected def value(): A
lazy val empty: A = value()

object DerivedEmpty:
type EmptyOrDerived[A] = Empty[A] OrElse DerivedEmpty[A]

def product[A](using inst: K0.ProductInstances[EmptyOrDerived, A]): DerivedEmpty[A] =
() => inst.construct([A] => (F: EmptyOrDerived[A]) => F.unify.empty)

inline def coproduct[A](using gen: K0.CoproductGeneric[A]): DerivedEmpty[A] =
() => K0.summonFirst[EmptyOrDerived, gen.MirroredElemTypes, A].unify.empty

inline given derived[A](using gen: K0.Generic[A]): DerivedEmpty[A] =
inline gen match
case given K0.ProductGeneric[A] => product
case given K0.CoproductGeneric[A] => coproduct

trait EmptyDerivation:
extension (E: Empty.type)
inline def derived[A](using gen: K0.ProductGeneric[A]): Empty[A] =
ProductEmpty(using K0.mkProductInstances)
inline def derived[A](using instance: DerivedEmpty[A]): Empty[A] = instance
21 changes: 21 additions & 0 deletions core/src/main/scala-3/cats/derived/orelse.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package cats.derived

enum OrElse[+A, +B]:
case Primary(value: A)
case Secondary(value: () => B)

final def fold[C](primary: A => C, secondary: B => C): C = this match
case Primary(value) => primary(value)
case Secondary(value) => secondary(value())

final def unify[C >: A](implicit ev: B <:< C): C = this match
case Primary(value) => value
case Secondary(value) => value()

object OrElse extends OrElseLowPriority:
inline given primary[A, B](using inline a: A): OrElse[A, B] =
OrElse.Primary(a)

private[derived] sealed abstract class OrElseLowPriority:
inline given secondary[A, B](using inline b: B): OrElse[A, B] =
OrElse.Secondary(() => b)
11 changes: 11 additions & 0 deletions core/src/test/scala-3/cats/derived/EmptyTests.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package cats.derived

import alleycats._
import cats._
import cats.derived.all._

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

0 comments on commit 8a49e4e

Please sign in to comment.