Created
May 13, 2019 23:57
-
-
Save lemastero/2d601115e4367aba8d1feb32b0010af9 to your computer and use it in GitHub Desktop.
Profunctor and Bifunctor can be expressed using 3 more basic abstractions. This nicely split organise laws for them.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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