Now, as far as type inference goes (and this should probably be a distinct question), for both languages it is incomplete, in the sense that you can always write an un-annotated program for which the compiler won't be able to determine the type.
for Haskell, this is because it has impredicative (a.k.a. first-class) polymorphism, for which type inference is undecidable. Note that on that point, Java is limited to first-order polymorphism (something on which Scala expands).
for Java, this is because it supports contravariant subtyping.
But those languages mainly differ in the range of program statements to which type inference applies in practice, and in the importance given to the correctness of the type inference results.
A
and B
in the example above) can be only instantiated with non-polymorphic types (I'm simplifying, but this is essentially the ML-style polymorphism you can find in e.g. Ocaml.).Prior to the release of Java 5, there was no type inference in Java. According to the Java language culture, the type of every variable, method, and dynamically allocated object must be explicitly declared by the programmer. When generics (classes and methods parameterized by type) were introduced in Java 5, the language retained this requirement for variables, methods, and allocations. But the introduction of polymorphic methods (parameterized by type) dictated that either (i) the programmer provide the method type arguments at every polymorphic method call site or (ii) the language support the inference of method type arguments. To avoid creating an additional clerical burden for programmers, the designers of Java 5 elected to perform type inference to determine the type arguments for polymorphic method calls. (source, emphasis mine)
The inference algorithm is essentially that of GJ, but with a somewhat kludgy addition of wildcards as an afterthought (Note that I am not up to date on the possible corrections made in J2SE 6.0, though). The large conceptual difference in approach is that Java's inference is local, in the sense that the inferred type of an expression depends only on constraints generated from the type system and on the types of its sub-expressions, but not on the context.
Note that the party line regarding the incomplete & sometimes incorrect type inference is relatively laid back. As per the spec:
Note also that type inference does not affect soundness in any way. If the types inferred are nonsensical, the invocation will yield a type error. The type inference algorithm should be viewed as a heuristic, designed to perform well in practice. If it fails to infer the desired result, explicit type parameters may be used instead.
Parametric polymorphism means, we don't care about the type, we'll implement the function the same for any type. For example, in Haskell:
length :: [a] -> Intlength [] = 0 length (x:xs) = 1 + length xs
We don't care what the type of the elements of the list are, we just care how many there are.
Ad-hoc polymorphism (aka method overloading), however, means that we'll use a different implementation depending on the type of the parameter.
Here's an example in Haskell. Let's say we want to define a function called makeBreakfast
.
If the input parameter is Eggs
, I want makeBreakfast
to return a message on how to make eggs.
If the input parameter is Pancakes
, I want makeBreakfast
to return a message on how to make pancakes.
We'll create a typeclass called BreakfastFood
that implements the makeBreakfast
function. The implementation of makeBreakfast
will be different depending on the type of the input to makeBreakfast
.
class BreakfastFood food wheremakeBreakfast :: food -> Stringinstance BreakfastFood Eggs wheremakeBreakfast = "First crack 'em, then fry 'em"instance BreakfastFood Toast wheremakeBreakfast = "Put bread in the toaster until brown"
According to John Mitchell's Concepts in Programming Languages,
The key difference between parametric polymorphism and overloading (aka ad-hoc polymorphism) is that parameteric polymorphic functions use one algorithm to operate on arguments of many different types, whereas overloaded functions may use a different algorithm for each type of argument.
A complete discussion of what parametric polymorphism and ad-hoc polymorphism mean and to what extent they're available in Haskell and in Java is longish; however, your concrete questions can be tackled much more simply:
How algorithm of type inference e.g. in Java difference from the type inference in Haskell?
As far as I know, Java does not do type inference. So the difference is that Haskell does it.
Please, give me an example of the situation where something can be written in Java/Scala but can not be written in Haskell(according to the modular features of these platforms too), and vice-versa.
One very simple example of something Haskell can do that Java can't is to define maxBound :: Bounded a => a
. I don't know enough Java to point out something it can do that Haskell can't.