Skip to content

Instantly share code, notes, and snippets.

@chrislewis
Created July 29, 2014 16:16
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chrislewis/0810c87333966a061990 to your computer and use it in GitHub Desktop.
Save chrislewis/0810c87333966a061990 to your computer and use it in GitHub Desktop.
import scala.language.higherKinds
trait Bifunctor[BF[_, _]] {
def bimap[A, B, C, D](bf: BF[A, C], fab: A => B, fcd: C => D): BF[B, D]
/* Mapping over one of the sides is convenient and can be implemented easily
in terms of `bimap`. */
/** Map over the "first" side, transforming the type and potentially the value
(if the BF instance is of the "first" type, natrually.) */
def map0[A, B, C](bf: BF[A, C], fab: A => B): BF[B, C] =
bimap(bf, fab, identity[C])
/** Map over the "second" side, transforming the type and potentially the
value (if the BF instance is of the "second" type.) */
def map1[A, C, D](bf: BF[A, C], fcd: C => D): BF[A, D] =
bimap(bf, identity[A], fcd)
}
object Instances {
val tuple2 =
new Bifunctor[Tuple2] {
def bimap[A, B, C, D](bf: (A, C), fab: A => B, fcd: C => D): (B, D) =
(fab(bf._1), fcd(bf._2))
}
val eitherBifunctor =
new Bifunctor[Either] {
def bimap[A, B, C, D](bf: Either[A, C], fab: A => B, fcd: C => D): Either[B, D] =
bf match {
case Left(l) => Left(fab(l))
case Right(r) => Right(fcd(r))
}
}
}
/*
scala> val e: Either[String, Int] = Right(1)
e: Either[String,Int] = Right(1)
scala> def hi(s: String) = "Hi " + s
hi: (s: String)String
scala> def incr(i: Int) = i + 1
incr: (i: Int)Int
scala> Instances.eitherBifunctor.bimap(e, hi, incr)
res0: Either[String,Int] = Right(2)
scala> Instances.eitherBifunctor.map0(e, hi)
res1: Either[String,Int] = Right(1)
scala> Instances.eitherBifunctor.map1(e, incr)
res2: Either[String,Int] = Right(2)
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment