I was talking to a friend about the differences between the type systems of Haskell and Java. He asked me what Haskell's could do that Java's couldn't, and I realized that I didn't know.

After thinking for a while, I came up with a very short list of minor differences. Not being heavy into type theory, I'm left wondering whether they're formally equivalent.

To try and keep this from becoming a subjective question, I'm asking: what are the major, non-syntactical differences between their type systems? I realize some things are easier/harder in one than in the other, and I'm not interested in talking about those.

And to make it more specific, let's ignore Haskell type extensions since there's so many out there that do all kinds of crazy/cool stuff.

There are either too many possible answers, or good answers would be too long for this format. Please add details to narrow the answer set or to isolate an issue that can be answered in a few paragraphs.
If this question can be reworded to fit the rules in the help center, please edit the question.

4

I too am curious to hear the long winded category theorists answer to this question; though I doubt I will particularly understand it, I am still interested in a detailing of this. My inclination from things I've read is that the HM type system allows the compiler to know a ton about what your code does which is why it is capable of inferring types so much as well as giving so many guarantees about the behavior. But that's just my gut instinct and I'm sure there are other things to it which I'm utterly unaware of.
–
Jimmy HoffaOct 8 '12 at 16:07

1

This is a great question - time to tweet it out to followers for the great Haskell/JVM debate!
–
Martijn VerburgOct 8 '12 at 16:17

1

@Matt Fenwick Being a functional language Haskell has built in support for higher-order functions; you can easily apply map or reduce over a list in Haskell for example. Of course the same functionality can be provided with Java also, but not directly.
–
m3th0dmanOct 8 '12 at 16:36

5

@m3th0dman: Scala has the exact same support for higher-order functions as Java has. In Scala, first-class functions are simply represented as instances of abstract classes with a single abstract method, just like Java. Sure, Scala has syntactic sugar for defining these functions, and it has a rich standard library of both pre-defined function types and methods that accept functions, but from a type system perspective, which is what this question is about, there is no difference. So, if Scala can do it, then Java can, too, and in fact there are Haskell-inspired FP libraries for Java.
–
Jörg W MittagOct 8 '12 at 16:41

6

@m3th0dman They're perfectly ordinary types. There's nothing special about lists except some synactic niceties. You can easily define your own algebraic data type that's equivalent to the built-in list type except for the literal syntax and the names of the constructors.
–
sepp2kOct 8 '12 at 18:38

Principal typing

This one is difficult to give a direct example of, but it means that every expression has exactly one maximally general type (called its principal type), which is considered the canonical type of that expression. In terms of "constraint-based" subtype polymorphism (see above), the principal type of an expression is the unique subtype of every possible type that that expression can be used as. The presence of principal typing in (unextended) Haskell is what allows complete type inference (that is, successful type inference for every expression, without any type annotations needed). Extensions that break principal typing (of which there are many) also break the completeness of type inference.

Don't use l as a single letter variable, it is VERY difficult to distinguish from 1!
–
recursion.ninjaSep 29 '13 at 19:32

5

It may be worth noting, that while you are absolutely right that Java has some runtime type information and Haskell does not, you can use the Typeable type-class in Haskell to provide something which behaves like runtime type information for many types (with newer PolyKinded classes on the way, it will be all types iirc), although I think it depends on the situation whether it actually passes any type information at runtime or not.
–
DarkOtterSep 30 '13 at 14:25

3

@DarkOtter I'm aware of Typeable, but Haskell 2010 does not have it (maybe Haskell 2014 will?).
–
Ptharien's FlameSep 30 '13 at 15:13

5

What about (closed) sum types? They're one of the more important mechanisms for encoding constraints.
–
tibbeSep 30 '13 at 20:12

One thing nobody's mentioned so far is type inference: a Haskell compiler can usually infer the type of expressions but you have to tell the Java compiler your types in detail. Strictly, this is a feature of the compiler but the design of the language and type system determines whether type inference is feasible. In particular, type inference interacts badly with Java's subtype polymorphism and ad hoc overloading. In contrast, the designers of Haskell try hard not to introduce features that impact type inference.

Another thing people don't seem to have mentioned so far is algebraic data types. That is, the ability to construct types from sums ('or') and products ('and') of other types. Java classes do products (field a and field b, say) fine. But they don't really do sums (field a OR field b, say). Scala has to encode this as multiple case classes, which isn't quite the same. And while it works for Scala it's a bit of a stretch to say Java has it.

Haskell can also construct function types using the function constructor, ->. While Java's methods do have type signatures, you can't combine them.

Java's type system does enable a type of modularity that Haskell hasn't got. It will be a while before there's an OSGi for Haskell.

To complement the other answers, Haskell's type system doesn't have subtyping, while typed object oriented languages as Java do.

In programming language theory, subtyping (also subtype polymorphism or inclusion polymorphism) is a form of type polymorphism in which a subtype is a datatype that is related to another datatype (the supertype) by some notion of substitutability, meaning that program elements, typically subroutines or functions, written to operate on elements of the supertype can also operate on elements of the subtype. If S is a subtype of T, the subtyping relation is often written S <: T, to mean that any term of type S can be safely used in a context where a term of type T is expected. The precise semantics of subtyping crucially depends on the particulars of what "safely used in a context where" means in a given programming language. The type system of a programming language essentially defines its own subtyping relation, which may well be trivial.

Due to the subtyping relation, a term may belong to more than one type. Subtyping is therefore a form of type polymorphism. In object-oriented programming the term 'polymorphism' is commonly used to refer solely to this subtype polymorphism, while the techniques of parametric polymorphism would be considered generic programming...

Mind running that by us again, in English this time? :P
–
Mason WheelerOct 8 '12 at 16:33

7

@Matt: As an example I can't write this in Java, but I can write the equivalent in Haskell: <T<_> extends Collection> T<Integer> convertStringsToInts(T<string> strings). The idea here would be that if someone called it as convertStringsToInts<ArrayList> it would take an arraylist of strings and return an arraylist of integers. And if they instead used convertStringsToInts<LinkedList>, it'd be the same with linked lists instead.
–
sepp2kOct 8 '12 at 18:32

@JörgWMittag: My understanding is that higher-rank polymorphism concerns where you can put the forall in your types. In Haskell, a type a -> b is implicitly forall a. forall b. a -> b. With an extension, you can make these foralls explicit and move them around.
–
Tikhon JelvisOct 9 '12 at 3:51

Yep, some of these were on my short list of minor differences ... I decided not to include them because 1,2,3 aren't really about the type system, 4 is orthogonal to the expressive power or formal properties of the type system, and I'm not sure about 5.
–
user39685Oct 8 '12 at 17:49

3

Yes, especially lazy evaluation is not a property of a type system. You can have lazy-evaluated languages with no type system at all and vice versa. Points 2. and 3. are syntactical differences.
–
Petr PudlákOct 8 '12 at 21:17

@KristopherMicinski an infinite type is something like (a -> a -> ...) not a lazily evaluated value.
–
WesSep 30 '13 at 17:39

3

To clarify: The OP is confusing the type language and the value language. You can have recursive types like data List a = Cons a | Nil but that is a finite type, not an infinite one, although it can be used to construct "infinite" data structures.
–
WesSep 30 '13 at 17:49