One of the things that really interested me was how how easy it is to compose lists. Take the function below that can generate a list of files from a directory and any subsequent subdirectories:
let rec allFiles dir =
[for file in System.IO.Directory.GetFiles dir do
for subDir in System.IO.Directory.GetDirectories dir do
yield! allFiles subDir]
I'm essentially looping through every file and yielding it into the list. F# intrinsically knows to throw the data into a list because of the brackets. I don't have to worry about creating "objects" to store the data--I treat the data as a function. Also notice the "yield!" statement. The exclamation point tells F# that you want to yield the results of another list into the list. In this case, because I marked the function as recursive("rec"), I can simply recursively call each branch of the file directories until I reach the leaf node.
Here is what this function would look like in C#:
public static List
var allFiles = new List
foreach(var file in Directory.GetFiles(dir))
foreach (var subDir in Directory.GetDirectories(dir))
getAllFiles(subDir).ForEach(file => allFiles.Add(file));
As you can see, F# is much more compact and fluent in expressing functions.