Not to whore myself horribly but I wrote a couple F# overview posts on my blog here and here. Chris Smith (guy on the F# team at MS) has an article called 'F# in 20 minutes' - part 1 and part 2.
Note you have to be careful as the latest CTP of F# (version 1.9.6.0) has some seriously breaking changes compared to previous versions, so some examples/tutorials out there might not work without modification.
Here's a quick run-down of some cool stuff, maybe I can give you a few hints here myself which are clearly very brief and probably not great but hopefully gives you something to play with!:-
First note - most examples on the internet will assume 'lightweight syntax' is turned on. To achieve this use the following line of code:-
#light
This prevents you from having to insert certain keywords that are present for OCaml compatibility and also having to terminate each line with semicolons. Note that using this syntax means indentation defines scope. This will become clear in later examples, all of which rely on lightweight syntax being switched on.
If you're using the interactive mode you have to terminate all statements with double semi-colons, for example:-
> #light;;
> let f x y = x + y;;
val f : int -> int -> int
> f 1 2;;
val it : int = 3
Note that interactive mode returns a 'val' result after each line. This gives important information about the definitions we are making, for example 'val f : int -> int -> int' indicates that a function which takes two ints returns an int.
Note that only in interactive do we need to terminate lines with semi-colons, when actually defining F# code we are free of that :-)
You define functions using the 'let' keyword. This is probably the most important keyword in all of F# and you'll be using it a lot. For example:-
let sumStuff x y = x + y
let sumStuffTuple (x, y) = x + y
We can call these functions thus:-
sumStuff 1 2
3
sumStuffTuple (1, 2)
3
Note there are two different ways of defining functions here - you can either separate parameters by whitespace or specify parameters in 'tuples' (i.e. values in parentheses separated by commas). The difference is that we can use 'partial function application' to obtain functions which take less than the required parameters using the first approach, and not with the second. E.g.:-
let sumStuff1 = sumStuff 1
sumStuff 2
3
Note we are obtaining a function from the expression 'sumStuff 1'. When we can pass around functions just as easily as data that is referred to as the language having 'first class functions', this is a fundamental part of any functional language such as F#.
Pattern matching is pretty darn cool, it's basically like a switch statement on steroids (yeah I nicked that phrase from another F#-ist :-). You can do stuff like:-
let someThing x =
match x with
| 0 -> "zero"
| 1 -> "one"
| 2 -> "two"
| x when x < 0 -> "negative = " + x.ToString()
| _ when x%2 = 0 -> "greater than two but even"
| _ -> "greater than two but odd"
Note we use the '_' symbol when we want to match on something but the expression we are returning does not depend on the input.
We can abbreviate pattern matching using if, elif, and else statements as required:-
let negEvenOdd x = if x < 0 then "neg" elif x % 2 = 0 then "even" else "odd"
F# lists (which are implemented as linked lists underneath) can be manipulated thus:-
let l1 = [1;2;3]
l1.[0]
1
let l2 = [1 .. 10]
List.length l2
10
let squares = [for i in 1..10 -> i * i]
squares
[1; 4; 9; 16; 25; 36; 49; 64; 81; 100]
let square x = x * x;;
let squares2 = List.map square [1..10]
squares2
[1; 4; 9; 16; 25; 36; 49; 64; 81; 100]
let evenSquares = List.filter (fun x -> x % 2 = 0) squares
evenSqares
[4; 16; 36; 64; 100]
Note the List.map function 'maps' the square function on to the list from 1 to 10, i.e. applies the function to each element. List.filter 'filters' a list by only returning values in the list that pass the predicate function provided. Also note the 'fun x -> f' syntax - this is the F# lambda.
Note that throughout we have not defined any types - the F# compiler/interpreter 'infers' types, i.e. works out what you want from usage. For example:-
let f x = "hi " + x
Here the compiler/interpreter will determine x is a string since you're performing an operation which requires x to be a string. It also determines the return type will be string as well.
When there is ambiguity the compiler makes assumptions, for example:-
let f x y = x + y
Here x and y could be a number of types, but the compiler defaults to int. If you want to define types you can using type annotation:-
let f (x:string) y = x + y
Also note that we have had to enclose x:string in parentheses, we often have to do this to separate parts of a function definition.
Two really useful and heavily used operators in F# are the pipe forward and function composition operators |> and >> respectively.
We define |> thus:-
let (|>) x f = f x
Note that you can define operators in F#, this is pretty cool :-).
This allows you to write things in a clearer way, e.g.:-
[1..10] |> List.map (fun x -> x * x) |> List.filter (fun x -> x % 2 = 0)
Will allow you to obtain the first 10 even squares. That is clearer than:-
List.filter (fun x -> x % 2 = 0) (List.map (fun x -> x * x) [1..10])
Well, at least I think so :-)
Function composition defined by the >> operator is defined as follows:-
let (>>) f g x = g(f(x))
I.e. you forward-pipe an operation only the parameter of the first function remains unspecified. This is useful as you can do the following:-
let mapFilter = List.map (fun x -> x * x) >> List.filter (fun x -> x % 2 = 0)
Here mapFilter will accept a list an input and return the list filtered as before. It's an abbreviated version of:-
let mapFilter = l |> List.map (fun x -> x * x) |> List.filter (fun x -> x % 2 = 0)
If we want to write recursive functions we have to define the function as recursive by placing 'rec' after the let. Examples below.
Some cool stuff:-
Factorial
let rec fact x = if x <= 1 then 1 else x * fact (x-1)
nth Fibonacci Number
let rec fib n = if n <= 1 then n else fib (n-1) + fib (n-2)
FizzBuzz
let (/%) x y = x % y = 0
let fb = function
| x when x /% 15 -> "FizzBuzz"
| x when x /% 3 -> "Fizz"
| x when x /% 5 -> "Buzz"
| x -> x.ToString()
[1..100] |> List.map (fb >> printfn "%s")
Anyway that's a very brief overview, hopefully it helps a little!!