Why not compiler check the type when using equal?

I am trying this code:

let a x = x + 1
let b x = x + 1
let _ = print_endline "abc"
let c = a = b

but I got runtime error.(Exception: (Invalid_argument “compare: functional value”))
Why OCaml compiler do not check the type? It can check if type is a function then throw a error on compiling.
Why it do not?

# (=) ;;
- : 'a -> 'a -> bool = <fun>

= is a curried two-argument function.

1 Like

I think this is an interesting question. IIUC, in some Standard ML dialects, they define “equality types”, i.e. the limited set of types that allow for equality comparison (=). So you cannot check two functions or programs for equality - because they are not equality types.

I don’t really understand whether this is/would-have-been possible to do in OCaml, or whether there are theoretical limitations / practical tradeoffs (e.g. maybe it would require whole program compilation), and I really could not find anything from googling either.

Would be great if someone could explain why it is the way it is in OCaml.


One observation is that (=) is partially defined even when comparing values containing functions:

# let a = (3, 5, 7, sin);;
val a : int * int * int * (float -> float) = (3, 5, 7, <fun>)
# let b = (3, 5, 8, cos);;
val b : int * int * int * (float -> float) = (3, 5, 8, <fun>)
# a = b;;
- : bool = false

You can also have types like (float -> float) option whose values may or may not contain functions in particular cases.

So, if you forbid comparisons between types containing functions you forbid certain cases that might be useful. Still it’s a good question.

1 Like

Both of a & b are int -> int, I think.

What about only check when <fun> = <fun>?

I think this is the cause of the problem.

This is not possible for abstract types.



The compiler cannot check that two types can be compared by the memory representation equality in the general case because that would require breaking abstraction.

The (=) operator is mostly an useful default implementation of equality that behaves nicely on some types, but it is not really expected to be used for all types. Typically, base shadows this polymorphic operator to avoid potential misuse. Overall, adding one type class (with the loss of modularity that this implies) to the language for the sake of this lone function was not judged worth it in term of language complexity.