fun length [] = 0\n | length (x::xs) = 1 + length xs\n val a = length [1,2,3,4]\n val b = length ["a","b","c","d"]
This should give the answer of 4. Notice no types were explicitly declared here. The compiler figures out that the first invocation is a length of integers and the second a list of strings. The length function can operate over lists of all types, so there is no need to declare the types.
Referential Transparency: This roughly means that for a given set of inputs, the function should always generate the same results. State is the natural enemy of RI, in that it can change the result of a function. So the first rule of thumb is that there should not be a dependency upon external state.
val a = ref 0\n fun nontransparent x = x + !a\n val b = nontransparent 1;\n a := !a + 1;\n val c = nontransparent 1
The results are b=1 and c=2, but the function calls were identical. The external state variable a got changed in between. This would be a violation of RI.
The other enemy of RI is sequencing. FP languages come in two flavors - eager and lazy. Eager languages evaluate the function parameters prior to calling the function. Lazy languages don't evaluate parameters until the values are needed (forced).
Higher Order Functions: Functions can be first class values. They can be parameters to functions and returned as values from functions. The three most common are: Map, Filter, and Fold (aka Reduce).
val x = map (fn i => i+i) [1,2,3,4]\n (* result: x = [1,4,6,8] *)\n\n val y = filter (fn a => (a < 3)) [1,2,3,4]\n (* result: y = [1,2] *)\n\n val z = foldr (fn (x,y) => x+y) 0 [1,2,3,4]\n (* result: z = 10 *)\n\n val z = foldl (fn (x,y) => x+y) 0 [1,2,3,4]\n (* result: z = 10 *)
Map applies a given function to each element within a list and returns the resulting list. Filter returns a list of items within the input list that have the function evaluate to true. Fold collapses the list by applying a function across the list and returning the value of the function. Fold can be either Left or Right, depending on whether you wont to fold the list starting from the left side and working your way right (or vice versa).
As Scott said, many of these things are also in non-FP languages. But the point of FP is one of emphasis - having features which make working with functions easier. Haskell is the only FP language that's considered to be close to pure. ML and Scheme have state variables (like the above ML code). Haskell is a pursuit to use monads to handle the reality of needing to cope with external events but manage them in a pure FP fashion.