Chapter 1. Introduction to F#

F# is a powerful language that spans multiple paradigms of development. This chapter provides a brief introduction to the heart of F#—the F# compiler, tools, and its place in Visual Studio 2010.

In this chapter, you will create a couple of simple F# applications and then I’ll point out key Visual Studio features for F# development. I won’t cover much of Visual Studio here, so I encourage you to explore the IDE on your own to learn more, or refer to the documentation online at http://msdn.microsoft.com/en-us/vstudio/default.aspx.

If you are already familiar with Visual Studio, you should still skim through this chapter. Creating and debugging F# projects works just like C# or VB.NET; however, F# has a unique characteristic when it comes to multiple-file projects. In addition, F# has a feature called F# Interactive that will dramatically increase your productivity. Not to be missed!

Getting to Know F#

As with all programming books, it is customary to write a Hello, World application, and I don’t want to deviate from tradition. Open up Notepad or your favorite text editor and create a new file named HelloWorld.fs with the following text:

// HelloWorld.fs

printfn "Hello, World"

Success! You’ve just written your first F# application. To compile this application, use the F# compiler, fsc.exe, located in the Program Files\Microsoft F#\v4.0 folder. (Or, if you are using the Mono, wherever you chose to install F#.) The following snippet shows calling the F# compiler on the command line to build and run your application:

C:\Program Files\Microsoft F#\v4.0>fsc HelloWorld.fs
Microsoft F# Compiler, (c) Microsoft Corporation, All Rights Reserved
F# Version 1.9.8.0, compiling for .NET Framework Version v4.0.21017

C:\Program Files\Microsoft F#\v4.0>HelloWorld.exe
Hello, World!

Visual Studio 2010

Tools are the lifeblood of any programming language, and F# is no different. While you can be successful writing F# code in your favorite text editor and invoking the compiler exclusively from the command line, you’ll likely be more productive using tools. Like C# and VB.NET, F# is a first-class citizen in Visual Studio. F# in Visual Studio has all the features you would expect, such as debugger support, IntelliSense, project templates, and so on.

To create your first F# project, open up the Visual Studio IDE and select File→New Project from the menu bar to open the New Project dialog, as shown in Figure 1-1. Select Visual F# in the left pane, select F# Application in the right pane, and click OK.

Select F# Application to start your first F# project
Figure 1-1. Select F# Application to start your first F# project

After you click OK in the New Project dialog, you’ll see an empty code editor, a blank canvas ready for you to create your F# masterpiece.

To start with, let’s revisit our Hello, World application. Type the following code into the F# editor:

printfn "Hello, World"

Now press Control + F5 to run your application. When your application starts, a console window will appear and display the entirely unsurprising result shown in Figure 1-2.

Hello, World in F#
Figure 1-2. Hello, World in F#

Your Second F# Program

It may be startling to see a program work without an explicit Main method. You will see why this is admissible in the next chapter, but for now let’s create a more meaningful Hello, World–type program to get a feel for basic F# syntax.

The code in Example 1-1 will create a program that accepts two command-line parameters and prints them to the console. In addition, it displays the current time.

Example 1-1. Mega Hello World
(*
Mega Hello World:
Take two command line parameters and then print
them along with the current time to the console.
*)

open System

[<EntryPoint>]
let main (args : string[]) =

    if args.Length <> 2 then
        failwith "Error: Expected arguments <greeting> and <thing>"

    let greeting, thing = args.[0], args.[1]
    let timeOfDay = DateTime.Now.ToString("hh:mm tt")

    printfn "%s, %s at %s" greeting thing timeOfDay

    // Program exit code
    0

Now that you have actual F# code, hopefully you are curious about what is going on. Let’s look at this program line by line to see how it works.

Values

Example 1-1 introduces three values named greeting, thing, and timeOfDay:

    let greeting, thing = args.[0], args.[1]
    let timeOfDay = DateTime.Now.ToString("hh:mm tt")

The key thing here is that the let keyword binds a name to a value. It is worth pointing out that unlike most other programming languages, in F# values are immutable by default, meaning they cannot be changed once initialized. We will cover why values are immutable in Chapter 3, but for now it is sufficient to say it has to do with functional programming.

F# is also case-sensitive, so any two values with names that only differ by case are considered different:

let number = 1
let Number = 2
let NUMBER = 3

A value’s name can be any combination of letters, numbers, an underscore _, or an apostrophe '. However, the name must begin with a letter or an underscore.

Note

You can enclose the value’s name with a pair of tickmarks, in which case the name can contain any character except for tabs and newlines. This allows you to refer to values and functions exposed from other .NET languages that may conflict with F# keywords:

let ``this.Isn't %A% good value Name$!@#`` = 5

Whitespace Matters

Other languages, like C#, use semicolons and curly braces to indicate when statements and blocks of code are complete. However, programmers typically indent their code to make it more readable anyway, so these extra symbols often just add syntactic clutter to the code.

In F#, whitespace—spaces and newlines—is significant. The F# compiler allows you to use whitespace to delimit code blocks. For example, anything indented more than the if keyword is considered to be in the body of the if statement. Because tab characters can indicate an unknown number of space characters, they are prohibited in F# code.

Note

You can configure the Visual Studio editor to automatically convert tab characters into spaces by changing the relevant setting under Tools→Options→Text Editor→F#.

Reviewing Example 1-1, notice that the body of the main method was indented by four spaces, and the body of the if statement was indented by another four spaces:

let main (args : string[]) =

    if args.Length <> 2 then
        failwith "Error: Expected arguments <greeting> and <thing>"

    let greeting, thing = args.[0], args.[1]
    let timeOfDay = DateTime.Now.ToString("hh:mm tt")

    printfn "%s, %s at %s" greeting thing timeOfDay

    // Program exit code
    0

If the body of the if statement, the failwith, was dedented four spaces and therefore lined up with the if keyword, the F# compiler would yield a warning. This is because the compiler wouldn’t be able to determine if the failwith was meant for the body of the if statement:

[<EntryPoint>]
let main (args : string[]) =

    if args.Length <> 2 then
    failwith "Error: Expected arguments <greeting> and <thing>"

Warning FS0058: possible incorrect indentation: this token is offside of
context started at position (25:5). Try indenting this token further or
using standard formatting conventions

The general rule is that anything belonging to a method or statement must be indented further than the keyword that began the method or statement. So in Example 1-1, everything in the main method was indented past the first let and everything in the if statement was indented past the if keyword. As you see and write more F# code, you will quickly find that omitting semicolons and curly braces makes the code easier to write and also much easier to read.

.NET Interop

Example 1-1 also demonstrated how F# can interoperate with existing .NET libraries:

open System

// ...

let timeOfDay = DateTime.Now.ToString("hh:mm tt")

The .NET Framework contains a broad array of libraries for everything from graphics to databases to web services. F# can take advantage of any .NET library natively by calling directly into it. In Example 1-1, the DateTime.Now property was used in the System namespace in the mscorlib.dll assembly. Conversely, any code written in F# can be consumed by other .NET languages.

For more information on .NET libraries, you can skip ahead to Appendix A for a quick tour of what’s available.

Comments

Like any language, F# allows you to comment your code. To declare a single-line comment, use two slashes, //; everything after them until the end of the line will be ignored by the compiler:

    // Program exit code

For larger comments that span multiple lines, you can use multiline comments, which indicate to the compiler to ignore everything between the (* and *) characters:

(*
Mega Hello World:
Take two command line parameters and then print
them along with the current time to the console.
*)

For F# applications written in Visual Studio, there is a third type of comment: an XML documentation comment. If a comment starting with three slashes, ///, is placed above an identifier, Visual Studio will display the comment’s text when you hover over it.

Figure 1-3 shows applying an XML documentation comment and its associated tooltip.

XML documentation comments
Figure 1-3. XML documentation comments

F# Interactive

So far you have written some F# code and executed it, and the rest of the book will have many more examples. While you could leave a wake of new projects while working through this book and trying out the samples, Visual Studio comes with a tool called F# Interactive or FSI. Using the FSI window, you will not only find it much easier to work through the examples in this book, but it will also help you write applications.

F# Interactive is a tool known as a REPL, which stands for read-evaluate-print loop. It accepts F# code, compiles and executes it, then prints the results. This allows you to quickly and easily experiment with F# code without needing to create new projects or build a full application to see the result of a five-line snippet.

In C# and VB.NET, you must compile and then run your application in order to see its results, which makes it cumbersome to try out and experiment with small code fragments. Even if you use the Visual Studio Immediate Window while debugging, you are limited to just evaluating expressions and cannot actually write code, such as defining new functions and classes.

In Visual Studio, most profiles launch the F# Interactive window by using the Control+Alt+F keyboard combination. Once the FSI window is available, it accepts F# code until you terminate the input with ;; and a newline. The code entered will be compiled and executed just as shown in Figure 1-4.

After each code snippet is sent to FSI, for every name introduced, you will see val <name>. If an expression was left unnamed, by default, it will be called it. After the name of the identifier will be a colon and the type of the code evaluated, followed by its value. For example, in Figure 1-4, the value x was introduced, of type int, with value 42.

Note

If you are running F# without Visual Studio, you can find a console version of F# Interactive named fsi.exe in the same directory you found fsc.exe.

Try running these other snippets in FSI. Note that every code snippet is terminated with ;;:

> 2 + 2;;
val it : int = 4
> // Introduce two values
let x = 1
let y = 2.3

val x : int
val y : float

> float x + y;;
val it : float = 3.3
> let cube x = x * x * x;;

val cube : int -> int

> cube 4;;
val it : int = 64

FSI dramatically simplifies testing and debugging your applications because you can send F# code from your current project to the FSI window by highlighting the code in Visual Studio and pressing Alt+Enter.

The F# Interactive window
Figure 1-4. The F# Interactive window

After selecting all the code in Example 1-1 within the code editor and pressing Alt+Enter, you will see the following in the FSI window:

>

val main : string array -> int

This allows you to write code in the Visual Studio editor—which offers syntax highlighting and IntelliSense—but test your code using the FSI window. You can test the main method you sent to FSI simply by calling it:

> main [| "Hello"; "World" |];;
Hello, World at 10:52 AM
val it : int = 0

Note

The majority of the samples in this book are taken directly from FSI sessions. I encourage you to use FSI as well to follow along and experiment with the F# language’s syntax.

Managing F# Source Files

When you are starting out in F# programming, most of the programs you write will live only in FSI or perhaps in a single code file. Your F# projects, however, will quickly grow and be broken up across multiple files and eventually multiple projects.

The F# language has some unique characteristics when it comes to managing projects with multiple source files. In F#, the order in which code files are compiled is significant.

You can only call into functions and classes defined earlier in the code file or in a separate code file compiled before the file where the function or class is used. If you rearrange the order of the source files, your program may no longer build!

Note

The reason for this significance in compilation order is type inference, a topic covered in the next chapter.

F# source files are compiled in the order they are displayed in Visual Studio’s Solution Explorer, from top to bottom. Whenever you add a new code file, it is added to the bottom of the list, but if you want to rearrange the source files, you can right-click a code file and select Move Up or Move Down, as shown in Figure 1-5. The keyboard shortcut for reordering project files is Alt+Up and Alt+Down.

Now that you are armed with the logistical know-how for compiling F# applications, the rest of this book will focus exclusively on the syntax and semantics of the F# programming language.

Reordering files within an F# project
Figure 1-5. Reordering files within an F# project

Get Programming F# now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.