Skip to content

Commit

Permalink
Add tests for BifunctorK
Browse files Browse the repository at this point in the history
  • Loading branch information
joroKr21 committed May 11, 2024
1 parent 7caad75 commit 0100f70
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,10 @@ object K21
[t[_[_], _[_]]] =>> [a[_], b[_]] =>> Kinds.Tail[t[a, b]]
]:

type Id1[t] = [f[_], g[_]] =>> f[t]
type Id2[t] = [f[_], g[_]] =>> g[t]
type Const[c] = [t[_], u[_]] =>> c

extension [T[_[_], _[_]], A[_], B[_]](gen: ProductGeneric[T])
inline def toRepr(o: T[A, B]): gen.MirroredElemTypes[A, B] =
Tuple.fromProduct(o.asInstanceOf).asInstanceOf[gen.MirroredElemTypes[A, B]]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

package shapeless3.deriving

import cats.data.{EitherK, Tuple2K}

// ADTs

object adts:
Expand Down Expand Up @@ -49,6 +51,12 @@ object adts:
quantity: F[Int]
) derives FunctorK

enum Lattice[F[_], G[_]] derives BifunctorK:
case Top(value: F[Int])
case Bot(value: G[Int])
case Meet(value: Tuple2K[F, G, Int])
case Join(value: EitherK[F, G, Int])

sealed trait OptionD[T]:
def fold: T = this match
case Given(t) => t
Expand Down
13 changes: 13 additions & 0 deletions modules/deriving/src/test/scala/shapeless3/deriving/deriving.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package shapeless3.deriving

import cats.Eval
import cats.data.{EitherK, Tuple2K}
import org.junit.Assert.*
import org.junit.Test
import shapeless3.deriving.adts.*
Expand Down Expand Up @@ -255,6 +256,18 @@ class DerivationTests:
val exp1 = HkCons(Some(42), HkCons(None, HkOne(Some(313))))
assert(FunctorK[HkNel].mapK(arg1)(OptionD.toOption) == exp1)

@Test
def bifunctorK(): Unit =
val bf = BifunctorK[Lattice]
val top = Lattice.Top[OptionD, OptionD](Given(100))
val bot = Lattice.Bot[OptionD, OptionD](Default(0))
val meet = Lattice.Meet[OptionD, OptionD](Tuple2K(Given(100), Default(0)))
val join = Lattice.Join[OptionD, OptionD](EitherK.left(Given(100)))
assert(bf.bimapK(top)(OptionD.fold, OptionD.toOption) == Lattice.Top[Id, Option](100))
assert(bf.bimapK(bot)(OptionD.fold, OptionD.toOption) == Lattice.Bot[Id, Option](None))
assert(bf.bimapK(meet)(OptionD.fold, OptionD.toOption) == Lattice.Meet[Id, Option](Tuple2K(100, None)))
assert(bf.bimapK(join)(OptionD.fold, OptionD.toOption) == Lattice.Join[Id, Option](EitherK.left(100)))

@Test
def bifunctor(): Unit =
val v0 = Bifunctor[ConsF]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ package shapeless3.deriving

import scala.annotation.tailrec
import scala.compiletime.*

import cats.Eval
import cats.data.{EitherK, Tuple2K}

// Type classes

Expand Down Expand Up @@ -343,7 +343,36 @@ object FunctorK:
inline def derived[F[_[_]]](using gen: K11.Generic[F]): FunctorK[F] = functorKGen

trait BifunctorK[F[_[_], _[_]]]:
def mapK[A[_], B[_], C[_], D[_]](fab: F[A, B])(f: A ~> C, g: B ~> D): F[C, D]
def bimapK[A[_], B[_], C[_], D[_]](fab: F[A, B])(f: A ~> C, g: B ~> D): F[C, D]

object BifunctorK:
inline def apply[F[_[_], _[_]]](using bf: BifunctorK[F]): BifunctorK[F] = bf

given [T]: BifunctorK[K21.Id1[T]] with
def bimapK[A[_], B[_], C[_], D[_]](at: A[T])(f: A ~> C, g: B ~> D): C[T] = f(at)

given [T]: BifunctorK[K21.Id2[T]] with
def bimapK[A[_], B[_], C[_], D[_]](at: B[T])(f: A ~> C, g: B ~> D): D[T] = g(at)

given [T]: BifunctorK[K21.Const[T]] with
def bimapK[A[_], B[_], C[_], D[_]](t: T)(f: A ~> C, g: B ~> D): T = t

given [T]: BifunctorK[[f[_], g[_]] =>> Tuple2K[f, g, T]] with
def bimapK[A[_], B[_], C[_], D[_]](fab: Tuple2K[A, B, T])(f: A ~> C, g: B ~> D): Tuple2K[C, D, T] =
Tuple2K(f(fab.first), g(fab.second))

given [T]: BifunctorK[[f[_], g[_]] =>> EitherK[f, g, T]] with
def bimapK[A[_], B[_], C[_], D[_]](fab: EitherK[A, B, T])(f: A ~> C, g: B ~> D): EitherK[C, D, T] =
EitherK(fab.run match
case Left(a) => Left(f(a))
case Right(b) => Right(g(b))
)

given bifunctorKGen[F[_[_], _[_]]](using inst: => K21.Instances[BifunctorK, F]): BifunctorK[F] with
def bimapK[A[_], B[_], C[_], D[_]](fab: F[A, B])(f: A ~> C, g: B ~> D): F[C, D] =
inst.map(fab)([f[_[_], _[_]]] => (bf: BifunctorK[f], fab: f[A, B]) => bf.bimapK(fab)(f, g))

inline def derived[F[_[_], _[_]]: K21.Generic]: BifunctorK[F] = bifunctorKGen

case class Fix[S[_, _], A](unfix: S[A, Fix[S, A]])

Expand Down

0 comments on commit 0100f70

Please sign in to comment.