Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Profunctor and Bifunctor can be expressed using 3 more basic abstractions. This nicely split organise laws for them.
import scala.language.higherKinds
trait LeftContravariant[F[_,_]] {
def contramap[A,AA,B](fa: F[A,B])(f: AA => A): F[AA,B]
}
trait RightCovariant[F[_,_]] {
def map[A,B,BB](fa: F[A,B])(g: B => BB): F[A,BB]
}
trait LeftCovariant[F[_,_]] {
def mapLeft[A,AA,B](fa: F[A,B])(g: A => AA): F[AA,B]
}
// can define LeftContravariant but there is no known to me examples of BiContravariant
trait Profunctor[F[_,_]] extends RightCovariant[F] with LeftContravariant[F] {
def dimap[AA,A,B,BB](fa: F[A,B])(f: AA => A, g: B => BB): F[AA, BB] =
map(contramap(fa)(f))(g)
}
trait Bifunctor[F[_,_]] extends RightCovariant[F] with LeftCovariant[F] {
def bimap[AA,A,B,BB](fa: F[A,B])(f: A => AA, g: B => BB): F[AA, BB] = {
val v1: F[A, BB] = map(fa)(g)
val v2: F[AA, BB] = mapLeft(v1)(f)
v2
}
}
/* Below not work
trait Functor[F[_]] extends RightCovariant[F[Nothing,_]] {
def map[B,BB](fa: F[B])(g: B => BB): F[BB]
}
trait Contravariant[F[_]] extends ContravariantDi[F[_, Nothing]]{
override def contramap[A,AA](fa: F[A])(f: AA => A): F[AA]
}
*/
// example LeftContravariant that is not a Profunctor or Bifunctor
case class Deamon()
trait Warlock[A,B] {
def summonDeamon(soulStone: B): Deamon
def trapSoul(creature: Any): B
def castSpell(): A
}
val leftCovariantWarlock: LeftCovariant[Warlock[?,?]] = new LeftCovariant[Warlock] {
def mapLeft[A, StrongerA, B](lock: Warlock[A, B])(improve: A => StrongerA): Warlock[StrongerA, B] =
new Warlock[StrongerA, B] {
def summonDeamon(soulStone: B): Deamon = lock.summonDeamon(soulStone)
def trapSoul(creature: Any): B = lock.trapSoul(creature)
def castSpell(): StrongerA = improve(lock.castSpell())
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.