Jul. 24th, 2013
You know the stupid problem with Java/Scala collections: their
Well, a natural transformation from a covariant functor to a contravariant is not only possible, it's a relatively popular thing. So, does it mean we can make
Questions? :)
I think it's cool; category theory applied directly to solve a code design problem.
contains()
method takes any type; the explanation being that for this method to be type-dependent, we need contravariance, while collections are (mostly) covariant. So there.Well, a natural transformation from a covariant functor to a contravariant is not only possible, it's a relatively popular thing. So, does it mean we can make
contains()
method type-dependent? The answer is YES!trait MyList[+T] { // declare a simple collection, e.g. list; it is covariant def head:T def tail:MyList[T] def ::[U>:T](x:U) = HeadAndTail(x, this) def size: Int } case object EmptyList extends MyList[Nothing] { // it's okay that it's a list of Nothing def head = error("This list is empty") def tail = error("this list is empty") def size = 0 } case class HeadAndTail[T](head:T, tail: MyList[T]) extends MyList[T] { def size = 1 + tail.size } // All the stuff above allows us to treat lists in a covariant way, like this: case class A(name: String) {override def toString = "A(" + name + ")"} case class B(override val name: String) extends A(name) {override def toString = "B(" + name + ")"} val listB = B("1") :: B("2") :: EmptyList listB.size must_== 2 val listA = A("3") :: listB listA.size must_== 3 val listC: MyList[Any] = listA // See, MyList is covariant, so if B is a subtype of A, List[B] is a subtype of List[A] And now... introduce a contravariant trait: trait Container[-T] { def contains(t:T): Boolean } // and the natural transformation from MyList[+T] to Container[-T]: implicit def asContainer[T](list:MyList[T]): Container[T] = new Container[T] { def contains(t:T) = list.size > 0 && (list.head == t || asContainer(list.tail).contains(t)) } And it works. I can draw the appropriate commutative diagrams later, if it is not obvious. listA contains A("3") must beTrue listA contains B("1") must beTrue // listA contains "abracadabra" is a compilation error listC contains "abracadabra" must beFalse listC contains B("2") must beTrue
Questions? :)
I think it's cool; category theory applied directly to solve a code design problem.