Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The purpose of type classes in Haskell vs the purpose of traits in Scala

I am trying to understand how to think about type classes in Haskell versus traits in Scala.

My understanding is that type classes are primarily important at compile time in Haskell and not at runtime anymore, on the other hand traits in Scala are important both at compile time and run time. I want to illustrate this idea with a simple example, and I want to know if this viewpoint of mine is correct or not.

First, let us consider type classes in Haskell:

Let's take a simple example. The type class Eq.

For example, Int and Char are both instances of Eq. So it is possible to create a polymorphic List that is also an instance of Eq and can either contain Ints or Chars but not both in the same List.

My question is : is this the only reason why type classes exist in Haskell?

The same question in other words:

Type classes enable to create polymorphic types ( in this example a polymorphic List) that support operations that are defined in a given type class ( in this example the operation == defined in the type class Eq) but that is their only reason for existence, according to my understanding. Is this understanding of mine correct?

Is there any other reason why type classes exist in ( standard ) Haskell?

Is there any other use case in which type classes are useful in standard Haskell ? I cannot seem to find any.

Since Haskell's Lists are homogeneous, it is not possible to put Char and Int into the same list. So the usefulness of type classes, according to my understanding, is exhausted at compile time. Is this understanding of mine correct?

Now, let's consider the analogous List example in Scala:

Lets define a trait Eq with an equals method on it. Now let's make Char and Int implement the trait Eq.

Now it is possible to create a List[Eq] in Scala that accepts both Chars and Ints into the same List ( Note that this - putting different type of elements into the same List - is not possible Haskell, at least not in standard Haskell 98 without extensions)!

In the case of the Haskell's List, the existence of type classes is important/useful only for type checking at compile time, according to my understanding.

In contrast, the existence of traits in Scala is important both at compile time for type checking and at run type for polymorphic dispatch on the actual runtime type of the object in the List when comparing two Lists for equality.

So, based on this simple example, I came to the conclusion that in Haskell type classes are primarily important/used at compilation time, in contrast, Scala's traits are important/used both at compile time and run time.

Is this conclusion of mine correct?

If not, why not ?

EDIT:

Scala code in response to n.m.'s comments:

case class MyInt(i:Int) {
  override def equals(b:Any)= i == b.asInstanceOf[MyInt].i
}

case class MyChar(c:Char) {
  override def equals(a:Any)= c==a.asInstanceOf[MyChar].c
}


object Test {
  def main(args: Array[String]) {
     val l1 = List(MyInt(1), MyInt(2), MyChar('a'), MyChar('b'))
     val l2 = List(MyInt(1), MyInt(2), MyChar('a'), MyChar('b'))
     val l3 = List(MyInt(1), MyInt(2), MyChar('a'), MyChar('c'))
     println(l1==l1)
     println(l1==l3)
  }
}

This prints:

true
false
like image 213
jhegedus Avatar asked Sep 21 '14 06:09

jhegedus


People also ask

Why do we use traits in Scala?

Traits are used to define object types by specifying the signature of the supported methods. Scala also allows traits to be partially implemented but traits may not have constructor parameters. A trait definition looks just like a class definition except that it uses the keyword trait.

What are type classes in Haskell?

Type Classes are a language mechanism in Haskell designed to support general overloading in a principled way. They address each of the concerns raised above. They provide concise types to describe overloaded functions, so there is no expo- nential blow-up in the number of versions of an overloaded function.

What is type class in Scala?

Type classes define classes of types in the same way types define classes of objects. In Scala, a type class means a trait with at least one type variable. For instance: trait CanChat[A] { def chat(x: A): String } This defines not just one type, but a set of types.

What are type classes used for?

Type classes are a powerful tool used in functional programming to enable ad-hoc polymorphism, more commonly known as overloading.


1 Answers

I will comment on the Haskell side.

Type classes bring restricted polymorphism in Haskell, wherein a type variable a can still be quantified universally, but ranges over only a subset of all the types -- namely, the types for which an instance of the type class is available.

Why restricted polymorphism is useful? A nice example would be the equality operator

(==) :: ?????

What its type should be? Intuitively, it takes two values of the same type and returns a boolean, so:

(==) :: a -> a -> Bool         -- (1)

But the typing above is not entirely honest, since it allows one to apply == to any type a, including function types!

(\x :: Integer -> x + x) == (\x :: Integer -> 2*x)

The above would pass type checking if (1) were the typing for (==), since both arguments are of the same type a = (Integer -> Integer). However, we can not effectively compare two functions: well-known Computability results tell us that there is no algorithm to do that in general.

So, what we could do to implement (==)?

Option 1: at run time, if a function (or any other value involving functions -- such as a list of functions) is found to be passed to (==), raise an exception. This is what e.g. ML does. Typed programs can now "go wrong", despite checking types at compile time.

Option 2: introduce a new kind of polymorphism, restricting a to the function-free types. For instance, ww could have (==) :: forall-non-fun a. a -> a -> Bool so that comparing functions yields to a type error. Haskell exploits type classes to obtain exactly that.

So, Haskell type classes allow one to type (==) "honestly", ensuring no error at run time, and without being overly restrictive. Of course, the power of type classes goes far beyond of that but, at least in my own view, they primary purpose is to allow restricted polymorphism, in a very general and flexible way. Indeed, with type classes the programmer can define their own restrictions on the universal type quantifications.

like image 178
chi Avatar answered Oct 10 '22 21:10

chi