|
When it comes to functions, there's ad hoc polymorphism, and there's parametric polymorphism. Parametric polymorphism is when you can define a function without knowing the precise type of its parameters. However, this limits what you can actually do with the parameters. For instance, a function concat([a], [a]) -> [a] which takes two lists containing items of type "a" knows enough about the type of its parameters (they're lists) to do its job, but it doesn't know everything about them. This is the type of polymorphism OCaml supports. Think of it as "one implementation, many types". That's why OCaml has more than one print function, and why it has integer and floating point versions of operators like + and *. Ad hoc polymorphism is when you can define implementations for a single function for whatever types you like. So you can implement add(Int, Int) -> Int, as well as add(Float, Float) -> Float. So this is "many implementations, many types." Haskell supports a version of this through typeclasses. OCaml doesn't currently support it, but the new "modular implicits" feature, as I understand it, will provide largely the same functionality. |
Haskell: concat :: [a] -> [a] -> [a]
OCaml: val concat : 'a list -> 'a list -> 'a list = <fun>
Both are parametrically polymorphic. However, in Haskell, I can use a type class to support ad-hoc polymorphism:
concat :: (Num a) => [a] -> [a] -> [a]
Now concat works forall a, as long as a is an instance of Num. This is important for arithmetic operators:
(+) :: (Num a) => a -> a -> a
Now I can have (+) be defined in a meaningful way, since Int, Integer, Float, etc. are all instances of Num, and implement (+). An easy way to think of this (since it's all it is, really) is operator/method overloading. In Haskell, (+) is overloaded for every type that you would want it to work for (the details of this are actually probably different, but are not important for learning).
In OCaml, if I have
val (+) : 'a -> 'a -> 'a = <fun>
There is actually only two implementations of that function:
let (+) a b = a
or
let (+) a b = b
Since I cannot restrict the set of types to the function, I can't do anything with the arguments. I don't know what the types are! Ad-hoc polymorphism allows for restricting the set of types, which allows for Haskell to use + for any Num-like thing.