juan_gandhi: (VP)
scala> val s = Set("a", "b", "c")
s: scala.collection.immutable.Set[String] = Set(a, b, c)

scala> val t = s.map(_ + ":)")
t: scala.collection.immutable.Set[String] = Set(a:), b:), c:))

scala> val s = Set("a1", "a2", "a3")
s: scala.collection.immutable.Set[String] = Set(a1, a2, a3)

scala> val t = s.map(_ take 1)
t: scala.collection.immutable.Set[String] = Set(a)

scala> val u:Set[Any] = s map identity
u: Set[Any] = Set(a1, a2, a3)

scala> val v:Set[Any] = s
<console>:8: error: type mismatch;
 found   : scala.collection.immutable.Set[String]
 required: Set[Any]
Note: String <: Any, but trait Set is invariant in type A.
You may wish to investigate a wildcard type such as `_ <: Any`. (SLS 3.2.10)
       val v:Set[Any] = s
                        ^


From a categorist's p.o.v, wtf, if we have map, we have a covariant functor. But wow, it's "type theory", covariance here means only covariance w.r.t. subtyping. So, big deal, map with identity, no? I mean, not being a typist, I don't even understand the problem. Do you?

so

Jul. 24th, 2013 09:37 pm
juan_gandhi: (VP)
You know the stupid problem with Java/Scala collections: their 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.
juan_gandhi: (Default)

Why is type inference failing here?

scala> val xs = List(1, 2, 3, 3)
xs: List[Int] = List(1, 2, 3, 3)

scala> xs.toSet map(_*2)
<console>:9: error: missing parameter type for expanded function ((x$1) => x$1.$times(2))
       xs.toSet map(_*2)

Profile

juan_gandhi: (Default)
Juan-Carlos Gandhi

September 2025

S M T W T F S
 1 2345 6
78 9 10 111213
14 151617 181920
212223 24252627
282930    

Syndicate

RSS Atom

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Sep. 27th, 2025 04:12 pm
Powered by Dreamwidth Studios