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 (v1.9.6.0) 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:
#light let square x = x * x let numbers = [1 .. 10] let squares = List.map square numbers printfn "N^2 = %A"squares open System Console.ReadKey(true)
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!
PingBack from http://www.bamor.net/chris-core-18791
Interesting posting!
It seems to require the full version of VS, though. How would one go about using it with free Express editions?
Brian and Chris have been writing some great blog posts of late on learning F#. I can highly recommend
Great introduction Chris!
@R, re: "require the full version of VS..?"
If you don't have Visual Studio, then you can run F Sharp Interactive as a console application (instead of a visual studio window).
The compiler and tools don't require Visual Studio -- they just offer Visual Studio integration as a "value add" feature.
Visual Studio express prohibits add-ons, so that kind of kills its ability to benefit from FSI. (Don Syme wrote answered a question about that here: http://cs.hubfs.net/forums/thread/3434.aspx )
Terrific! Just the right level of explanation that I badly need. Keep it up.
"Passing around functions as values is known as 'first order functions' and is a hallmark of functional programming."
No, it's called 'first-class functions' (because functions are first-class citizens, like, e.g., numbers) or 'higher-order functions' -- not 'first-order functions'. Languages with 'first-order functions' don't pass them around.
I appreciate your article, and just want to point out a couple of items that could perhaps be improved. For beginner's tutorials, little syntax errors can be confusing.
1. Under "printfn "N^2 = %A" squares", do you mean to say "printf is a simpler.." or "printfn is a simpler"? These look like two distinct things to me (I'm a noob obviously).
2. Under "let numbers = [1..10]", how're we supposed to type these lines into the FSI window? Exactly as is? Nothing happens. Do you intend for us to use the ";;" syntax to cause the line to execute? That yields an error. You might want to be a bit more explicit yet at this point to avoid frustrating your readers.
3. Under the picture of the FSI window, where you instruct your user to type "[1 .. 2 .. 10]" - an explanation of what the heck that IS, would be helpful here!
4. I'm guessing that "FSI" means "F Sharp Interactive" - but perhaps you could say that explicitly?
5. Where you give instructions on how to use the Add-in Manager to add the FSI window, you could stand to be a bit more explicit (IMO). You leave us with that Add-in Manager still open! What about those other two checkboxes - "Startup" and "Command Line"? Do you intend for us to click "OK" here before continuing on to your next step?
6. You skip a few beats in instructing your readers in creating their first F# project. "Add a new F# Source File"? Don't you need to let them know that they first need to create a project? And what about all that code and comments that come pre-loaded within that new F# source file I created? What's up with that? Do we need to delete it all first?
Minor quibble:
> 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.)
For C# we can make the distinction between definition and use. Definition is more verbose, due to the need for types, but it's not impossible either -- you simply use a Delegate type:
class List {
public static TOutput[] map<TInput, TOutput> (Func<Tnput, TOutput> f, TInput[] input) {...}
}
Usage would actually be similarly verbose to F#:
var squares = List.map (square, numbers);
List.map (x => x % 2 == 0, new int[]{1, /* ... */ 10});
The overhead here is the array creation, not the lambda expression.
(And in this case, using System.Array.Convert() would make more sense than defining a new List.map method.)
Thanks for the feedback, I'll update this post to (hopefully) clarify things more.
And if I need to remember to write out:
every time I pass declare method which takes a function as a parameter, I consider that hard to do. Even if the call-site code is clean ;)
Thanks,
-Chris
You can use F# with the free Visual Studio 2008 Shell. See the following for more info:
http://11011.net/archives/000721.html
http://fsharpnews.blogspot.com/2007/12/f-in-visual-studio-for-free.html
Great article; looking forward to the rest of the series. I've been meaning to look at F#, and this looks like a great quick intro.
On the comparison to C#, I'd like to echo the previous comment that it's actually quite easy to pass a function to a function. And, in fact, the System.Linq namespace already defines an equivalent of "map." Your full example looks something like this in C#:
using System;
using System.Linq;
class Program
{
static void Main()
Func<int, int> square = x => x * x;
int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var squares = numbers.Select(square);
Console.WriteLine("N^2 = {0}", squares.Aggregate("", (s, i) => s + " " + i));
Console.ReadKey(true);
Note that the hard part is declaring the sequence (which of course would be easier if there was an "Enumerable.Sequence" method or somesuch), and formatting the output.
Another approach, more in the spirit of the latest wave of C# features, would be:
static IEnumerable<int> Sequence(int start, int end)
for (int i = start; i < end; i++)
yield return i;
var squares = from x in Sequence(1, 10) select x * x;
And it's not true that declaring a function that takes a function arg is necessarily as verbose as declaring "map" is; that example is complicated by the fact that "map" has to be generic. I wonder what the declaration of "map" looks like in F#? Don't you have to do something special to keep the compiler from assuming all the types are "int," like it did for your "square" function?
Love the interactive evaluation thing. That might make me pick up F# all by itself.
Thanks again for the article!
Now that we have covered the basics, in minutes 8 - 14 we will cover the foundational concepts and types
从Allen Lee的《从C# 3.0到F#》一文开始,感觉园子里F#正在升温。Chris Smith写了一个F#的小系列,这里翻译出来与大家分享。在本文从零开始编写我们的第一个F#程序。
Tried to install the latest F# CTP where the platform is "Vista Ultimate" and VS 2008...hmmm - install dies saying that it not an appropriate MSI file???
Strange..
Ron
Hey Ron, could you be more specific. What was the exact error message you recieved? Please send it to fsbugs@microsoft.com.
Thanks!