I have known Scheme well for several years now and have been studying Ocaml for a few weeks. I like both languages very much and want to contrast them here. I have avoided the object portion of Ocaml so far.
The syntax of the two languages are at near opposite poles of design. Scheme programs can be easily dissected by counting parentheses whereas Caml programs require considerable knowledge of precedence of keywords. After a week Caml is easy to read.
The deeper differences are the attitudes towards type. In Scheme the primitive types are the atomic types, (number, character, string, bool, symbol), and the constructs, (pair, vector, procedure). The structures that typical Scheme programs use emerge only in the mind of the programmer, and as the Scheme program runs. By contrast a Caml compiler will not let the program out the gate until it has formed a satisfactory theory of the type that each expression of the program will assume as it runs. Caml has an explicit notion of type and type expressions that are included in some Caml programs. The Caml type notion is more restrictive than some Scheme programs practice but I have not found any important limitations yet.
Caml provides more primitive types where Scheme’s primitive types can each serve more styles. For instance my division algebra code uses a heterogeneous list to package the elements of an algebra. The emergent type of such a list is both the input and output of the Scheme function G. Scheme’s apply function conveniently binds a list of values to a list of names, making this hack convenient. Caml insists that lists be of uniform type but provides the module construct that suits the Caml version very well. Both languages allow redefinitions of familiar arithmetic operators and I exploit this. It is, after all, what algebras are about.
Here is a program that cannot be directly adapted to Caml. The pattern of the Scheme code
(let tst ((a reals)(names (list "reals" "complexes" "quaternions" "octonions" "sedenions" "32nions"))) (if (null? names) '() (cons (testAlg (car names) a) (tst (G a) (cdr names)))))excerpted from here, generates types dynamically—once per recursion of tst. This does not fit in the Caml module construct. It is not important in the case at hand because there were only a few iterations of interest. The Caml version conveniently produced the 5 types at compile time.
My program to do some combinatorial topology has no type expressions in it although it has some moderately complex types. The blue text below the program fragments shows the types inferred by the compiler. Most small changes to the code, even respecting syntax rules, will cause the compiler to find type misfits.
I have not found a careful description of Caml types but bouts with the Caml compiler teaches a great deal. The Caml tuple type constructor makes a type with some definite number of members, each of some definite type, and expressions of this type may be written (a, b, c, ...) where each of the sub expressions must be of the agreed type.