I think that one big idea that idiomatic OCaml programs use is “make illegal states unrepresentable,” a quote which I believe comes from OCamler Yaron Minsky. It means that OCaml programs should leverage the type system to make programs correct by construction, avoiding runtime checks when the programmer knows that the program cannot enter a certain state.
For example, say that a Foo is either a Bar, which has a name and an age, or a Baz, which only has an age. The “bad” way to express this, which might be done in languages without the strengths of OCaml’s type system, is
type foo = {
typ : string; (* typ is either "bar" or "baz" *)
name : string; (* should be "" if typ is "baz" *)
age : int;
}
The right way to do this is:
type bar = {
bar_name : string;
bar_age : int;
}
type baz = {
baz_age : int;
}
type foo = Bar of bar | Baz of baz
This idea can be taken further with GADTs, e.g. the post here about the well-typed parser ("Parsing" terms into a well-typed representation: a GADT puzzle).