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 11.
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.
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# program. To compile this
application, use the F# compiler, fsc.exe
,
located in the Program Files (x86)\Microsoft
SDKs\F#\3.0\Framework\v4.0 folder. (Don’t worry, you won’t have
to remember that.)
The following snippet shows calling the F# compiler on the command line to build and run your application:
C:\Programming F# Source\Ch01>fsc HelloWorld.fs
Microsoft (R) F# 3.0 Compiler build 11.0.50522.1 Copyright (c) Microsoft Corporation. All Rights Reserved. C:\Programming F# Source\Ch01>HelloWorld.exe
Hello, World!
Visual Studio 11
Tools are the lifeblood of any programming language, and F# is no different. Although you can successfully write F# code in your favorite text editor and invoke the compiler 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, with all the features that you might expect, including debugger support, IntelliSense, project templates, and so on.
Note
Alternatively, you can try F# out in your browser.
Let’s revisit our Hello, World application, but this time using Visual Studio.
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, which is shown in Figure 1-1. Select Visual F# in the left pane, select F# Application in the right pane, and then click OK.
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. Next, type the following code into the F# editor:
printfn
"Hello, World"
Now press Ctrl-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.
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 Chapter 2, 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.
// 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
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, values in F#
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,
underscores (_
), and apostrophes
('
). However, the name must begin
with a letter or an underscore.
Note
You can enclose the value’s name with a pair of tick marks, in which case the name can contain any character except for tabs and new lines. 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 (e.g., 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.
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 "..."
expression, was dedented four spaces and therefore lined up with the
if
keyword, the F# compiler would
produce a warning. This is because the compiler wouldn’t be able to
determine whether the failwith
was meant for the body of
the if
statement or the main
function:
[<
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 farther 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 much
easier to read.
.NET Interop
Example 1-1 also demonstrates how F# can interoperate with existing .NET libraries:
open
System
// ...
let
timeOfDay
=
DateTime
.
Now
.
ToString
(
"hh:mm tt"
)
This example shows the DateTime.Now
property from the System
namespace in the mscorlib.dll
assembly in use.
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. Conversely, any code written in F# can be consumed by other .NET languages. This also means that F# applications can run on any platform that supports .NET. So the F# programs you write can run on phones, tablets, PCs, and so on.
Note
For more information on .NET libraries, see Appendix A for a quick tour of what’s available. For more information about F# interoperating with other .NET languages, refer to Appendix B.
Comments
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, you can use (*
and *)
.
Everything between the two tokens will be ignored:
(*
Comment
spanning
multiple
lines
*)
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 the mouse over the
identifier.
Figure 1-3 shows applying an XML documentation comment and its associated tooltip.
F# Interactive
So far you have written some F# code and executed it, and the rest of the book will have many more examples. Although you could leave a wake of new projects to test out code, Visual Studio comes with a tool called F# Interactive or FSI. The FSI window will not only make 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# without needing to create new projects or build a full application to test the results of a code snippet.
Most Visual Studio configurations launch the F# Interactive window
with the Ctrl-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 is compiled
and executed as shown in Figure 1-4.
The FSI window prints any new values introduced as well as their
types. Figure 1-4 shows
val x : int = 42
, declaring that a
value x
of type int
was created with value 42
. If the FSI window evaluates an expression
that was not assigned to a value, it will instead assign it to the name
it
.
As the F# compiler processes FSI input, it will display the name,
type, and value of identifiers. For example, in Figure 1-4 the value x
was introduced with type int
and value 42
.
Note
If you are running F# without Visual Studio, you can find the
console version of F# Interactive in the same directory you found
fsc.exe
with the name fsi.exe
.
Try running these other snippets in FSI. Remember that every code
snippet is terminated with a
;;
:
> 2 + 2;; val it : int = 4 > // Introduce two values let x = 1 let y = 2.3;; val x : int = 1 val y : float = 2.3 > 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 can dramatically simplify testing and debugging your applications because you can send F# code from your current project to the FSI window by highlighting it and pressing Alt-Enter.
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 [] -> 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 check the main
method’s implementation by calling it from FSI:
> main [| "Hello"; "World" |];;
Hello, World at 10:52 AM
val it : int = 0
Note
The majority of the examples in this book are taken directly from FSI sessions. I encourage you to use FSI to follow along and experiment with the F# language’s syntax.
You can find a copy of the source code for all examples in the book on GitHub.
Managing F# Source Files
When you are starting out with 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 Chapter 2.
F# source files are compiled from top to bottom in the order they are displayed in Visual Studio’s Solution Explorer. Whenever you add a new code file it is added at 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 seen in Figure 1-5. The keyboard shortcut for reordering project files is Alt-Up and Alt-Down.
Warning
A feature sorely missing from Visual Studio is the ability to organize an F# project’s source code files into subfolders. Although not exposed by the Visual Studio UI, you can edit the project file directly to achieve this. Many of the in-depth examples of this book utilize this technique
Now that you are armed with the logistical know-how for creating, compiling, and testing F# applications, the rest of this book will focuses exclusively on the syntax and semantics of the F# programming language.
In just a few chapters, you’ll master the syntax of the F# language and be able to apply it across several programming paradigms. Good luck and have fun!
Get Programming F# 3.0, 2nd Edition 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.