Well, actually it's not a problem since I solved it but it bothers me too much :
Let's write this :
test.ml
type bop = Beq | Bneq | Badd
type value = Vint of int | Vchar of char
let eval bop a b =
let op = match bop with
| Beq -> (=)
| Bneq -> (<>)
in
match a, b with
| Vint i1, Vint i2 -> op i1 i2
| Vchar c1, Vchar c2 -> op c1 c2
| _ -> assert false
If I compile it I get :
ocamlc -o test test.ml File "test.ml", line 6, characters 11-62:
Warning 8: this pattern-matching is not exhaustive. Here is an example of a value that is not matched: Badd
Compilation finished at Tue Sep 13 13:24:50
Which is normal, I forgot to add the Badd
case.
So, since I hate warnings, I change my code to :
let eval bop a b =
let op = match bop with
| Beq -> (=)
| Bneq -> (<>)
| _ -> assert false (* or exit 1 or raise Exit *)
in
match a, b with
| Vint i1, Vint i2 -> op i1 i2
| Vchar c1, Vchar c2 -> op c1 c2
| _ -> assert false
And then I compile (and, as you can understand, here comes the disturbing part ;-)) and I get :
ocamlc -o test test.ml File "test.ml", line 13, characters 31-33:
Error: This expression has type char but an expression was expected of type int
Compilation exited abnormally with code 2 at Tue Sep 13 13:26:48
Well, what ? I figured out that the type of op
was not 'a -> 'a -> bool
but '_a -> '_a -> bool
and so I changed my code because I remembered about OCaml not allowing polymorphic types for non values and that partial applications are not values. It became :
let eval bop a b =
let op a b = match bop with
| Beq -> a = b
| Bneq -> a <> b
| _ -> assert false
in
match a, b with
| Vint i1, Vint i2 -> op i1 i2
| Vchar c1, Vchar c2 -> op c1 c2
| _ -> assert false
And after I compiled :
ocamlc -o test test.ml
Compilation finished at Tue Sep 13 13:29:48
I could have written :
let eval bop a b =
let op = match bop with
| Beq -> (=)
| Bneq -> (<>)
| _ -> Obj.magic
in
match a, b with
| Vint i1, Vint i2 -> op i1 i2
| Vchar c1, Vchar c2 -> op c1 c2
| _ -> assert false
and it compiles perfectly too (but, eww, Obj.magic is just a nickname to some lowlife OCaml programmer, right ?).
So, here is my question, how come that the compiler changes its behaviour when semantically I wrote exactly the same thing ? (I tested it with several versions of OCaml (3.12.1, 4.01.0, 4.02.3, 4.03.0)).
So, I prefer to answer in a simple way :
applications are monomorphic !
Actually, even better :
If you're not a function declaration, an identifier or a constant, you can't be polymorphic
But if you know that your type should be polymorphic, there is a way to do it by declaring it as a function. So, another way to make it polymorphic is to write :
let eval bop a b =
let op = match bop with
| Beq -> (=)
| Bneq -> (<>)
| _ -> fun _ -> assert false
in
match a, b with
| Vint i1, Vint i2 -> op i1 i2
| Vchar c1, Vchar c2 -> op c1 c2
| _ -> assert false
and another link to answer this : http://caml.inria.fr/pub/old_caml_site/FAQ/FAQ_EXPERT-eng.html#polymorphisme