Partager via


F# in 20 Minutes - Part I

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 https://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:

  • Part I - A slow introduction to F#, explaining your first program
  • Part II – A brisk overview of the foundational types and concepts in F#
  • Part III – A quick sampling into advanced topics

So if you're interested in seeing what the fuss is all about, the read on.

What is F# and why should I learn it?

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.

Getting Started

To get started with F# download and install the latest release (v1.9.6.0) at:
https://www.microsoft.com/downloads/details.aspx?FamilyID=61ad6924-93ad-48dc-8c67-60f7e7803d3c&displaylang=en

Or just click ‘Download’ on the F# Development center at https://msdn.com/fsharp

This will install the F# Project System on top of Visual Studio 2008. First, create a new F# Project.

image

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:

clip_image002

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.

F# Interactive for Visual Studio

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.)

Language Basics

#light (OCaml compat)

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.

let square x = x * x (Type Inference)

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.

let numbers = [1 .. 10] (F# Lists)

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.

let squares = List.map square numbers (List.map and first-order functions)

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.

printfn "N^2 = %A" squares

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.

Console.ReadKey(true) (.NET Interop)

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!

Comments

  • Anonymous
    May 02, 2008
    PingBack from http://www.bamor.net/chris-core-18791

  • Anonymous
    May 03, 2008
    Interesting posting! It seems to require the full version of VS, though. How would one go about using it with free Express editions?

  • Anonymous
    May 03, 2008
    Brian and Chris have been writing some great blog posts of late on learning F#. I can highly recommend

  • Anonymous
    May 03, 2008
    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 )

  • Anonymous
    May 03, 2008
    Terrific! Just the right level of explanation that I badly need. Keep it up.

  • Anonymous
    May 03, 2008
    "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.

  • Anonymous
    May 04, 2008
    The comment has been removed

  • Anonymous
    May 05, 2008
    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.)

  • Anonymous
    May 05, 2008
    Thanks for the feedback, I'll update this post to (hopefully) clarify things more. And if I need to remember to write out: public static TOutput[] map<TInput, TOutput> (Func<Tnput, TOutput> f, TInput[] input) {...} 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

  • Anonymous
    May 06, 2008
    @R, re: "require the full version of VS..?" 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

  • Anonymous
    May 06, 2008
    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;    }    static void Main()    {        var squares = from x in Sequence(1, 10) select x * x;        Console.WriteLine("N^2 = {0}", squares.Aggregate("", (s, i) => s + " " + i));        Console.ReadKey(true);    } 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!

  • Anonymous
    May 09, 2008
    Now that we have covered the basics, in minutes 8 - 14 we will cover the foundational concepts and types

  • Anonymous
    August 02, 2008
    从Allen Lee的《从C# 3.0到F#》一文开始,感觉园子里F#正在升温。Chris Smith写了一个F#的小系列,这里翻译出来与大家分享。在本文从零开始编写我们的第一个F#程序。

  • Anonymous
    September 07, 2008
    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

  • Anonymous
    September 07, 2008
    Hey Ron, could you be more specific. What was the exact error message you recieved? Please send it to fsbugs@microsoft.com. Thanks!

  • Anonymous
    September 08, 2008
    Good little intro to f#.  I used this for my initial lesson when learning f#.  If you're a VB programmer you may want to take a look at the series of blogs i've just started. http://blog.matthewdoig.com/?p=25

  • Anonymous
    September 08, 2008
    Unfortunately - as it seems, F# developers decided to use the way of the such aincient programming languages as Fortran - minimal type control, maximal possibility to make errors. If I am right, it's a mistake. The banner of this way could be expressed (using gross exaggeration in order not to say too much words) as follows - we will write the code as soon as possible (<all the rest will not be said to customers> but then we will look for the mistakes all the life remaining). Making mistakes is usual way for the middle-level programmer, F# will help him to do that?

  • Anonymous
    September 11, 2008
    The comment has been removed

  • Anonymous
    September 11, 2008
    whoops. I meant http://projecteuler.net

  • Anonymous
    September 11, 2008
    Since C# and F# both compile down to IL and get executed with the same JIT engine, there is no distinct speed 'advantage' for using one language over the other. F# should have the same performance profile as C#. Any significant difference in benchmarks is usually due to different algorithms being used.

  • Anonymous
    September 11, 2008
    Yes this is quite good . And what more advantanges with this lang.  

  • Anonymous
    September 17, 2008
    Hi I'd like to know (as mentioned by somebody above) what List.map square [1 .. 2 .. 10];; I can see from the result that it's outputting the squares of 1, 3, 5, 7 and 9 but I'm at a bit of a loss as to why! Thanks, great article by the way.

  • Anonymous
    September 17, 2008
    Excellent.. I am very much impressed the way you explained about the functional programming language F#. I also keep the specification document for F# when i am reading this post. Twice i turned to spec document for :: and @ operators meaning. Enjoyed writing F# code ... i am really become the fan of F# language after reading your blog. Thank you so much. Eagerly Waiting for second part. :)

  • Anonymous
    September 18, 2008
    There may be some performance advantage in the fact that F# does tail call optimization where it can (C#, in contrast, never does it).

  • Anonymous
    September 18, 2008
    Great introduction to F# for beginners, thanks.

  • Anonymous
    September 22, 2008
    @Rupert List.map square [1 .. 2 .. 10];; 2 must be increment by: 1+2=3+2=5+2=7+2=9

  • Anonymous
    September 24, 2008
    First, let me remind you that in my new ongoing quest to read source code to be a better developer ,

  • Anonymous
    September 24, 2008
    First, let me remind you that in my new ongoing quest to read source code to be a better developer ,

  • Anonymous
    September 25, 2008
    It can be even easier in C# than Eric's. MessageBox.Show(Enumerable.Range(1, 10).Select(a => a * a).Aggregate("", (b, c) => b + " " + c));

  • Anonymous
    September 30, 2008
    Very nice tutorial.  I hope to learn some F# soon and this really helped.

  • Anonymous
    October 01, 2008
    Just learn Python and use IronPython and be done with it. Too many languages create vertical markets. VB dropped "let" 20  years ago, why bring it back? I was hoping to see something tuly nice, and readable: numbers = range(1,10) print "N^2="+str([xx for x in numbers]) Oh wait, that is python. If you feel the need to use a map construct: def square(n):    return nn print "N^2="+str(map(square, numbers)) What is more readable?

  • Anonymous
    October 02, 2008
    F# is more readable and powerful, of course. There's no obligation about learning functional programming, but it's an important part from Computer Sciences, and, if you want to compare two different languages as Python and F#, you should know the basic concepts behind FPLs for making a sensible evaluation.

  • Anonymous
    October 06, 2008
    The comment has been removed

  • Anonymous
    October 07, 2008
    The problem is the way you declared the list: ['e';'i';'o';'u'] is a list of characters (semicolon delimited) ['e','i','o','u'] is a single-element list, which is a tuple of 4 characters. (Duples are comma delimited.) Make sense?

  • Anonymous
    October 09, 2008
    The reason it didn't work Srinivasan is because you separated the list elements with commas instead of semicolons. Comma separation creates a tuple, or compound type, so what you actually made there was a list with one element, a tuple of four chars, instead of a list with four char elements. This article should explain it better than I can: http://diditwith.net/2008/01/18/WhyILoveFTuples.aspx

  • Anonymous
    October 09, 2008
    Whoops, sorry Chris, for some reason your answer wasn't showing up on my browser until after I posted mine.

  • Anonymous
    October 16, 2008
    原文链接:http://www.cnblogs.com/anderslly/archive/2008/08/03/fs-in-20-minutes.html

  • Anonymous
    October 17, 2008
    You've been kicked (a good thing) - Trackback from DotNetKicks.com

  • Anonymous
    November 24, 2008
    Hello, The programs below are well received. However an expensive source code (MATLAB) is used. Several potential users would like to use an open source code like F#. Is it suitabel to use F# to solve differential equations? Research reactor http://www.euronuclear.org/e-news/e-news-20/neutron-flux.htm Chernobyl avalanche http://www.euronuclear.org/e-news/e-news-20/chernobyl-avalanche.htm

  • Anonymous
    November 25, 2008
    Re: "Is it suitabel to use F# to solve differential equations?" Certainly. F# seems to be very productive in highly algorithmic domains - e.g. the math and number crunching. As for the MatLab piece, I assume it is just a matter of finding the right math libraries and graphing libraries. Unfortunately I don't have any reccomendations for mathematical .NET libraries.

  • Anonymous
    November 25, 2008
    Thanks for Your answer. Could You recomend somebody I could turn to for answer?

  • Anonymous
    November 26, 2008
    I don't understand Alex's complaint about minimal type checking. As far as I can see, F# has quite strict type checking at compile time (much stricter than the C family of languages, for example). Maybe it's not obvious from the tutorial, because you don't have to /tell/ F# the type of an identifier if F# can unambiguously infer it.

  • Anonymous
    November 26, 2008
    Jason, you do realise that "let" in F# is completely unrelated to "let" in BASIC, don't you? The F# equivalent to BASIC's    LET A = 5 is    a <- 5 No sign of a "let". In F#, "let" means something quite different, that I don't think has a direct equivalent in non-functional languages (I suppose it has /some/ similarity to "&" in C++, because it's defining a sort of alias).

  • Anonymous
    December 02, 2008
    For those that still don't understand the [1 .. 2 .. 10] bit, it reminds me a bit of the FOR statement when used with the /L option: FOR /L (start, step, end) DO action Although I don't have much knowledge of the .NET library, it is reasonable to infer that "List.map square [1 .. 2 .. 10]" creates a list by mapping its elements to the result of calling square with arguments 1, 3, 5, 7 and 9 (because the step value is 2, and the constraints specified 1 to 10 inclusive).  The end result is that we end up with with the squares of the numbers above.  It also reminds me of list comprehensions in Python: >>> [square(i) for i in range(1, 11, 2)] [1, 9, 25, 49, 81] Of course, in Python, the range function excludes the upper limit, so 11 needs to be used rather than 10. I love these types of languages.  They can get so much done with such little code!

  • Anonymous
    December 09, 2008
    F# you can even write XBox games using XNA. I tried a small demo, it works very nicely. Selami Ozlu

  • Anonymous
    January 08, 2009
    Stupid Microsoft, this is just another VBscript. Stupid VBstscript, certainly stuoid F# again.

  • Anonymous
    January 16, 2009
    Just Learn Python instead. Get all the Dynamic stuff without the .net Framework. Why would you try to do dynamic stuff in the CLR? I tried doing a recursive lambda once in c#. nightmare and it doesn't work. The new stuff on DLR looks interesting though, although I am thinking of jumping ship to Python as it does all that I want and then some. Who needs stupid acronyms like LINQ when you got list comprehensions. If you really want the functional style then go Haskell, the only one that doesn't cause a stack overflow as far as I can tell.

  • Anonymous
    January 20, 2009
    It would be nice to see a better example of the advantages of F# over C#.  As a C# developer, I agree with some others that it just looks like some awkward syntax and easy way to code in more errors so far. Can you give an example of something F# can do that C# can't?

  • Anonymous
    January 28, 2009
    Why Caml (instead of - say - Haskell, Standard ML, or even Erlang)? Just curious - I don't consider this decision to be bad, after all...

  • Anonymous
    January 31, 2009
    @MarcinK - Haskell is pure FP, no OO construct.  Ocaml has the OO stuff that F# also supports.

  • Anonymous
    February 08, 2009
    F# is the new kid on the block in terms of .NET languages.&#160; Currently in CTP form , it will be one

  • Anonymous
    February 25, 2009
    F# has its roots in a programming language called OCaml, C# has its roots in a programming language called Java, Garbage Collection has its roots in Lisp, etc.

  • Anonymous
    February 25, 2009
    So why all this efforts to re-invent the wheel?

  • Anonymous
    March 03, 2009
    Good Article. But why I used F#, if I already have C#? If possible make a comparison among F#, C# and Java. Only for mathematical calculation, I will never usr F#.

  • Anonymous
    March 05, 2009
    The comment has been removed

  • Anonymous
    March 13, 2009
    It's nice to have had someone write a tutorial, but (IMHO) this one just leaves out too many concepts for a part-one.  It's borders on a turn-off, for what is basically a lot of clutter. It's not that I'm particularly dim-witted, having followed a language use path of FORTRAN->assembly->C->C++ , and C# when necessary (because MS didn't see fit to include the functionality in C++).  The [1..2..10] was (to me), an obvious syntax, given the results. I just think that a tutorial should <i>teach more and extol less</i>.  Again, this is an IMHO.

  • Anonymous
    March 23, 2009
    I read these comments and I wonder about if some of you even read anything about F# before you commented. I'm certainly not a F# evangelist as I only really started looking at it more closely in the past few weeks. It's interesting how many of the commenters don't understand "side effects" They keep asking what good is F#? WHy would I use this.. Etc. Etc. Perhaps you should watch the Anders interview about C# 4.0 they go off on a tangent that might help you understand.

  • Anonymous
    April 19, 2009
    @Eric Eilebrecht "Note that the hard part is declaring the sequence (which of course would be easier if there was an "Enumerable.Sequence" method or somesuch)" You could use Enumerable.Range

  • Anonymous
    April 23, 2009
    Nice Intro . I'm new to F#, enjoyed reading this article. F# looks similar to Matlab programming (.M code) .  

  • Anonymous
    April 30, 2009
    Next Chicago ALT.NET meeting will bring a practical look at F#, showing that it does not need to be seen

  • Anonymous
    May 06, 2009
    I did not try F# But based on this introduction, I think F# borrows the idea of Prolog

  • Anonymous
    May 26, 2009
    @Bui Viet Duc: F# is part of a family of so-called "functional languages". Examples of these languages are Haskell, LISP, Scheme. They also borrow some concepts from languages such as Prolog. They don't, however, copy their core ideals and syntax from Prolog.

  • Anonymous
    May 26, 2009
    第一篇,从零开始编写我们的第一个F#程序。 什么是F#,我为何要学它? F#是一种.NET平台上的 函数式编程 语言。就像C#和VB.NET,F#可以利用.NET的核心类库,如 WPF , WCF ,

  • Anonymous
    June 02, 2009
    Great article. Will definitely be reading up more on F#. Just wish that MS would offer lisp as well.

  • Anonymous
    June 11, 2009
    I suspect for a beginner this might not be the most friendy introduction...

  • Anonymous
    June 11, 2009
    It's a great article to know about F#.