I've been playing around with the ML language recently, using the OCaml implementation.

Picking up ML illustrates to me why it's useful to learn a number of different languages in order to experience various styles of programming - it's sometimes not enough that a language merely 'supports' a particular style; sometimes the language must live that style for the user to fully get it.

For example, lots of languages support 'currying' of functions by allowing the user to return anonymous closures. However ML is the first language I've used that embraces currying as the basis for implementing multi-argument functions - i.e. in ML, multi-argument functions are literally just nested single argument functions.

For example, in the following expression:

let sum = fun i j -> i + j

the type of 'sum' is:

int -> int -> int 

..meaning that 'sum' is a function that takes an integer and returns a function which takes an integer and returns an integer.

In addition OCaml's function-call syntax doesn't use brackets, which allows the call to be considered by the user as both as a multiple-arg function call or as a bunch of nested calls. E.g. in

sum 3 4

the above could be read either as 'invoke the 'sum' function with the arguments 3 and 4', or alternatively as 'invoke the 'sum' function with an argument 3, and then invoke the result of that with the argument 4'.