Skip to content

Instantly share code, notes, and snippets.

@kubukoz
Last active May 20, 2021 20:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kubukoz/5f6dd415eb3345a8300d91cfc6209a10 to your computer and use it in GitHub Desktop.
Save kubukoz/5f6dd415eb3345a8300d91cfc6209a10 to your computer and use it in GitHub Desktop.
Deriving typeclass instances for higher-kinded type in Scala 3
// This could be very useful for https://github.com/kubukoz/datas/blob/2d7ba9d1b4974bc03500c556279152ce441226ea/core/src/main/scala/datas/tagless.scala
trait TraverseK[Alg[_[_]]]:
def traverseK[F[_], G[_]: Applicative, H[_]](alg: Alg[F])(fk: F ~> ([a] =>> G[H[a]])): G[Alg[H]]
def sequenceK[F[_]: Applicative, G[_]](alg: Alg[[a] =>> F[G[a]]]): F[Alg[G]] =
traverseK(alg)(FunctionK.id)
def mapK[F[_], G[_]](af: Alg[F])(fk: F ~> G): Alg[G] = traverseK[F, cats.Id, G](af)(fk)
def sequenceKId[F[_]: Applicative](alg: Alg[F]): F[Alg[cats.Id]] = sequenceK[F, cats.Id](alg)
object TraverseK:
extension [Alg[_[_]]: TraverseK, F[_]](alg: Alg[F])
def sequenceKId(using Applicative[F]) = summon[TraverseK[Alg]].sequenceKId(alg)
def mapK[G[_]](fk: F ~> G) = summon[TraverseK[Alg]].mapK(alg)(fk)
private[example] def toTuple(list: List[Any]): Tuple = list match
case h :: t => h *: toTuple(t)
case Nil => EmptyTuple
def derived[Alg[_[_]]](using s: Mirror.Product { type MirroredType[F[_]] = Alg[F] }): TraverseK[Alg] = new TraverseK[Alg]:
import cats.implicits.*
def traverseK[F[_], G[_]: Applicative, H[_]](alg: Alg[F])(fk: F ~> ([a] =>> G[H[a]])): G[Alg[H]] =
alg.asInstanceOf[Product].productIterator.toList.map(field => fk(field.asInstanceOf[F[Any]])).sequence.map { listHAny =>
s.fromProduct(toTuple(listHAny)).asInstanceOf[Alg[H]]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment