Edit: If you are interested in learning F#, let me take the opportunity to provide a shameless plug for my book Programming F#.
Edit: Updated for the September CTP.
Edit: While I certainly encourage you to read my blog, there is a great video we did for PDC titled An Introduction to Microsoft F# at http://channel9.msdn.com/pdc2008/TL11/
With the September CTP hot off the presses, I figured it was time to write a concise, 20-minute introduction to F#. The goal isn't to teach F#, but rather give a quick overview of the language and some of the things you can do with it. I’ll divide the 20 minutes into three parts:
So if you're interested in seeing what the fuss is all about, the read on.
F# is a functional programming language built on .NET. Just like C# and VB.NET, F# can take advantage of core libraries such as Windows Presentation Foundation, Windows Communication Foundation, Visual Studio Tools for Office, etc. With F# you can even write XBox games using XNA.
But just because you can write code in a new language doesn't mean you should. So why use F#? Because being a functional language, F# makes writing some classes of programs much easier than its imperative cousins like C#. Parallel Programming and Language-Oriented Programming are two such domains that can be expressed easily in F#.
If you’ve ever written a .NET application and found yourself fighting against the language to get your idea expressed, then perhaps F# is what you’ve been looking for.
To get started with F# download and install the latest release (v22.214.171.124) at: http://www.microsoft.com/downloads/details.aspx?FamilyID=61ad6924-93ad-48dc-8c67-60f7e7803d3c&displaylang=en
Or just click ‘Download’ on the F# Development center at http://msdn.com/fsharp
This will install the F# Project System on top of Visual Studio 2008. First, create a new F# Project.
Next, add a new F# Source File. By default it will add a lot of ‘tutorial’ code, delete all that and insert the following into the empty code editor:
let square x = x * x
let numbers = [1 .. 10]
let squares = List.map square numbers
printfn "N^2 = %A"squares
Press F5 to run your program, and you'll see the following:
Nothing terribly exciting yet. Let’s will break the code down the code line by line and then see if what’s really going on, but before we do that, let me introduce VFSI.
The F# Interactive Console (FSI) is what’s know as a ' REPL loop’ for Read-Evaluate-Print-Loop. This means: taking a code snippet, compiling and executing it, then printing the results. With it you can rapidly prototype and test your programs. To launch FSI simply highlight some code and press ALT+ENTER; the FSI window will immediately pop up.
What you just did was send the code snippet directly to the F# Interactive session, and the results were displayed to the output. The result was the definition of a function 'square' which takes a type 'int' and returns a type 'int'.
Next try typing "List.map square [1 .. 2 .. 10];;" into the FSI window. The ';;' indicates to FSI to stop reading in program text and evaluate the result.
> List.map square [1 .. 2 .. 10];;
val it : int list = [1; 9; 25; 49; 81]
Now we have the ability to easily explore the F# language via FSI, let's go into what that code actually means. I recommend however that you type code inside the Visual Studio code editor and use 'Highlight + ALT + Enter' to send the code to FSI. Otherwise, you will have to retype your code very time you have a typeo. (Which, at least for me, is very often.)
F# has its roots in a programming language called OCaml and has the ability to cross compile OCaml code, meaning that it can compile simple OCaml programs unmodified. This ability however, means that F# requires some unsavory syntax by default. #light (pronounced hash-light) is a compiler directive that simplifies the syntax of the language.
I highly recommend that you keep #light on since most F# code snippets you find will either declare it, or assume that it has been declared.
This defines a function called 'square' which squares a number x. Consider for a moment the equivalent C# code:
public static int square(int x)
return x * x;
Whereas C# requires you to specify type information as well as what the function actually returns, the F# compiler simply figures it out for you. This is referred to as type inference.
From the function signature F# knows that square takes a single parameter named 'x' and that the function would return 'x * x'. (That last thing evaluated in a function body is the ‘return value’, so no need for a ‘return’ keyword.) Since many primitive types support (*) such as byte, uint64, double, etc. F# defaults to int, a signed 32-bit integer.
Now consider the following code which provides a 'type annotation' for one of the parameters, that is telling the compiler the type to expect. Since x is stated to be of type 'string', and (+) is only defined for taking two strings, then the parameter y must also be a string. And the result of x + y is the concatenation of both strings.
> let concat (x : string) y = x + y;;
val concat : string -> string -> string
> concat "Hello, " "World!";;
val it : string = "Hello, World!"
We'll cover more advanced topics in type inference later. But for now just enjoy the fact that the F# compiler has the smarts to figure out what you mean, and doesn't require any hand holding.
The next line simply declares a list of numbers one through ten. If you had typed [|1 .. 10|] that would have created a .NET array of integers. But an F# list is an immutable linked list, which is the backbone of functional programming. Try typing these things into the FSI window (remember to add a ‘;;’ at the end of each line):
// Define a list
let vowels = ['e'; 'i'; 'o'; 'u']
// Attach item to front (cons)
let cons = 'a' :: vowels
// Concat two lists
let sometimes = vowels @ ['y']
I’ll cover lists more in-depth in Part II.
Now we have a list of integers ('numbers') and a function ('square'), we want to create a new list where each item is the result of calling our function. In other words, mapping our function to each item in the list.
Fortunately, List.map does just that. Consider another example:
> List.map (fun x -> x % 2 = 0) [1 .. 10];;
val it : bool list
= [false; true; false; true; false; true; false; true; false; true]
The code (fun i -> i % 2 = 0) defines an anonymous function, called a lambda expression, that has a parameter x and the function returns the result of "x % 2 = 0", which is whether or not x is even.
Now notice what we just did - we passed a function as a parameter to another function. You simply can't do that in C#. (At least not easily.) But in F# it allowed us to be very expressive and succinct in our code. Passing around functions as values is known as 'first order functions' and is a hallmark of functional programming.
printf is a simple and type-safe way to print text to the console window. To get a better feel for how printf works consider this example which prints an integer, floating-point number, and a string:
> printfn "%d * %f = %s" 5 0.75 ((5.0 * 0.75).ToString());;
5 * 0.750000 = 3.75
val it : unit = ()
The %d, %f, and %s are holes for integers, floats, strings. %A may also be used to print anything else.
The last line in our program was simply a call to System.Console.ReadKey, in order to pause the program before it closed. Since F# is built on top of .Net you can call any .NET library from F# - from Regular Expressions to WinForms. The line ‘open System’ simply opened the namespace and brought its types into scope, similar to the using keyword of C#.
Now that we have the absolute basics out of the way, we can move onto the more interesting foundational types and concepts of F# so stay tuned for Part II!