Skip to content

Instantly share code, notes, and snippets.

@Kazark
Created August 5, 2020 19:09
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 Kazark/35b9ad1772d85c3a8221b4a45a2f5278 to your computer and use it in GitHub Desktop.
Save Kazark/35b9ad1772d85c3a8221b4a45a2f5278 to your computer and use it in GitHub Desktop.
Cats .widen (covariant functors) and .narrow (contravariant functors): both are for upcasts, and thus safe
package example
import cats._
import cats.implicits._
sealed trait List[+A]
case object Nil extends List[Nothing]
final case class Cons[A](head: A, tail: List[A]) extends List[A]
final case class Co[I, A](run : I => A)
object Co {
implicit def cofunctor[I]: Functor[Co[I, *]] = new Functor[Co[I, *]]() {
override def map[A,B](x: Co[I, A])(f: A => B): Co[I, B] =
Co(x.run andThen f)
}
}
final case class Contra[O, A](run : A => O)
object Contra {
implicit def contrafunctor[O]: Contravariant[Contra[O, *]] = new Contravariant[Contra[O, *]]() {
override def contramap[A,B](x : Contra[O, A])(f: B => A): Contra[O, B] =
Contra(f andThen x.run)
}
}
object Example {
import Co._
def singleton[A]: Co[A, Cons[A]] =
Co { x => Cons(x, Nil) }
def single[A]: Co[A, List[A]] =
singleton[A].widen
def badHead[A]: Contra[A, List[A]] =
Contra { xs =>
xs match {
case Nil => throw new IllegalArgumentException()
case Cons(x, _) => x
}
}
def head[A]: Contra[A, Cons[A]] =
badHead[A].narrow
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment