9.3 First-class overloading
In ML, some of commonly used primitives are overloaded. For example, binary addition + can be used on several types included int, real, word as shown below.
# 1 + 1;
val it = 2 : int
# 1.0 + 1.0;
val it = 2.0 : real
# 0w1 + 0w1;
val it = 0wx2 : word
Different from polymorphic functions, a different implementation for + (i.e. one of Int.+, Real.+, Word.+ in the above example)is selected based on the context in which it is used. In Standard ML this overloading is resolved at the top-level at the end of each compilation unit. If there remain multiple possibilities then a predetermine one is selected. For example, if you write
fun plus x = x + x
in Standard ML, then Int.+ is selected for + and plus is bound to a function of type int -> int.
This strategy works fine, but this will become a big obstacle in integrating SQL, where most of the primitives are overloaded. If we determine the types of all the primitives in a SQL query at the time of is definition, then we cannot make full use of ML polymorphism in dealing with databases. For this reason, SML# introduces a mechanism to treat overloaded primitive functions as first-class functions. For explain, SML# infers the following polymorphic type for plus.
# fun plus x = x + x;
val plus = fn : [’a::{int, word, int8, word8, ...}. ’a -> ’a]
This function can be used as a function of any type obtained by replacing ’a with one of int, word, int8, word8, int16, word16, int64, word64, intInf, real, real32 (int16, are omitted). The constraint ’a::{...} on type variable ’a indicates the set of allowable instance types.