F#, the latest member of the Visual Studio family of languages, offers some enticing advantages over C# and Visual Basic, stemming from its functional-object fusion nature.

Originally a research language from Microsoft Research, F# has long been a “secret weapon” in the arsenal of .NET programmers for doing statistical- and mathematical-heavy coding. More recently, however, a growing number of developers have begun to see the inherent advantages implicit in writing functional code, particularly in the areas of concurrency. The buzz has begun to approach interesting levels, particularly on the heels of an announcement last year from the head of the Microsoft Developer Division, Somasegar, that F# would be “productized” and fully supported by Microsoft as a whole, suddenly removing the stigma and licensing restrictions that surround research projects.

One of the more recent ideas that’s sweeping the industry is the notion of “domain-specific languages,” (DSLs) whereby a developer builds a language that others (typically either skilled knowledge workers/subject matter experts, or sometimes even other programmers) will use to solve the particular business problems facing them. As Neal Ford describes, two different kinds of DSLs permeate the space: internal DSLs, built on top of an existing language’s syntax, and external DSLs, built in some of the same ways that languages like C# and Visual Basic are, with a parser, abstract syntax tree to store the parsed code, and either an interpreter to run the resulting program or a code generator to turn it into an executable program.

F# espouses several core key ideas: namely that static typing is a good safeguard to writing good code so long as the type information can stay out of the programmer’s way (also known as type inferencing), that functions are values and have first-class semantics right alongside integers and strings, that shared and/or mutable state should be minimized (if not avoided outright), and that functional design permits and encourages composition and substitutability.

As it turns out, F#, being derived from a long line of functional languages, has many of the tools necessary to make it easy to create simple external DSLs: discriminated unions, pattern matching, and combinatorial processing, all of which will probably be meaningless terms to the reader who’s never ventured outside of the object-oriented realm before. In this article, I’ll go over the basic syntax of F#, paying close attention to both those concepts that closely mirror that of the traditional O-O languages, as well as those that are brand new to the C#/VB programmer. While it’s entirely unreasonable to expect to master the F# language (or any non-trivial language) in a single column, by the end of this, F# should at least be recognizable and readable, leading the .NET programmer into diving more deeply into F# if and when appropriate.

Concepts

F# is a CLR-adapted version of the Object-CAML language, also known as OCaml. As a functional language, F# espouses several core key ideas, namely that static typing is a good safeguard to writing good code so long as the type information can stay out of the programmer’s way (also known as type inferencing), that functions are values and have first-class semantics right alongside integers and strings, that shared and/or mutable state should be minimized (if not avoided outright), and that functional design permits and encourages composition and substitutability (which is where F# and other functional languages get much of their reputation for being “mathematical” languages).

Some of these concepts are more subtle than it may seem at first; for example, type inferencing means less explicit code needed to make the compiler happy, which in turn not only means that you can express the same concepts in less code in F#, but also that much of the verbosity of generics in C# effectively “fall away” when writing similar code in F#.

Before going too deeply into a more conceptual discussion, a quick glance at some F# code may help put a framework around some of these ideas.

Setup

Before any F# coding can take place, you must install the F# binaries. As of this writing, F# still resides on the Microsoft Research Web site, the latest version is 1.9.4.17 and is most easily found via the F# Web site there-simply visit http://research.microsoft.com/fsharp/fsharp.aspx and find the latest release link from the announcements column on the right-hand side (the actual download URL changes with each release).

When installed, F# will not only put several executables, assemblies, and assorted samples into the installation directory, but will also register its Visual Studio language service support. This registration gives the F# developer much the same development experience as the C# or VB developer, with an added bonus: an extra tool window called interactive mode, which allows the F# developer to type some F# code and execute it immediately, much as the Immediate Window works in the debugger. Simply “swipe” some code from the editor window with the mouse, hit Alt-Enter, and the text will be automagically pasted and executed in the Interactive Window. (This is by far the easiest way to explore the language and its concepts.) Note that the F# package will also install into the Visual Studio Isolated Shell, so programmers who don’t have a copy of the commercial Visual Studio bits can still play along.

Assuming F# has installed successfully, fire up Visual Studio, create a new F# Project (under the “Other Project Types” node), add a new item (“F# Source file”), and call it file1.fs (the default). Notice that when you open the new file, the compiler populates it with a large number of F# example snippets, which serve as an easy way of getting started with the language. Have a look at the code in that template file later; for now, delete it all and replace it with the following code: F#’s version of the ubiquitous “Hello world” program:

#light
    
let language = "F#"
printfn "Hello, %A" language

Congratulations! You are now an F# programmer.

“Let” There Be F#

The core of the F# language is, in many ways, the “let” expression. In the grand tradition of mathematics, where “let” was always used to establish the preconditions of a mathematical proof, F#’s “let” binds a value to an identifier, where the value can be either a traditional value, such as “12” or “Amanda” or some other constant, or a function taking zero or more inputs into the function for processing. Thus, in the following:

let x = 5
let y = 12
let xtimesy x y = x * y

F# recognizes that x is bound to the value 5, y is bound to the value 12, and that xtimesy is bound to the function value “x * y”. Already, even in this simple code snippet, one of F#’s core concepts comes to the fore: not only does F# realize that the values of “x” and “y” have to be integers (System.Int32, in fact) because of the fact that they are each bound to an integer constant, but also that the inputs to “xtimesy” must be integers, based on the fact that the definition is doing multiplication.

In the grand tradition of mathematics, where “let” was always used to establish the preconditions of a mathematical proof, F#’s “let” binds a value to an identifier, where the value can be either a traditional value, such as “12” or “Amanda” or some other constant, or a function taking zero or more inputs into the function for processing.

This type inference behavior isn’t perfect, by the way; because F# has inferred that the inputs should be integers, passing floating-point values in will cause F# to register it as an error:

printfn "xtimesy 5 12 = %d" (xtimesy 5 12)
printfn "xtimesy 5.0 12.0 = %d" (xtimesy 5.0 12.0)

The first line will be OK, but the second will be flagged as an error by the Visual Studio environment, since the only definition of xtimesy currently requires integers. (Remember, F# is a statically typed language, despite what the terseness and lack of type information in the code may imply.) To fix this, you need a new definition of “xtimesy” that accepts floats, as well.

(Actually, as it turns out, F# doesn’t permit overloading of functions at this level, though it is OK with doing it inside of types; to make the above code work, you have to write it this way:

let xtimesy x y = x * y
let xtimesyf (x:double) (y:double) = x * y
    
printfn "xtimesy 5 12 = %d" (xtimesy 5 12)
printfn "xtimesyf 5.0 12.0 = %f"
  (xtimesyf 5.0 12.0)

By defining a new function, “xytimesyf”. Within the functional community, however, doing this kind of overloading is rarely done inside of F#, thanks to other features of the language, such as automatic inference of generic arguments.)

Note that the use of x and y in the function xtimesy is not bound against the x and y previously defined-like C#, F# has scope rules that say that names “inside” a new scope trump names from an outer scope. This applies, by the way, to nested functions just as it does to nested classes in C#.

In the second definition of “xtimesy”, the function definition chooses not to allow F# to infer the arguments (which it could do, since later in the program “xtimesyf” is used with floating-point values), but to explicitly declare the inputs to the function, each as a double. The parentheses are necessary here to help separate the one argument from the second; without them, an error will occur.

Normally, in F#, you can leave off the type designators, leaving F# to, in many cases, infer even more generic arguments about code than the original developer intended; for example, consider this function, which takes a tuple (pair) of arguments and reverses them:

let swap (a, b) = (b, a)

F# interprets this function to take two arguments, of any particular type (they don’t even have to be the same type), essentially turning this into a generic function along the lines of a C# function written like so:

public static Tuple<U, T> swap<T, U>(T a, U b)
{
    return new Tuple<U, T>(b, a);
}

In fact, glancing at the implementation of the F# code in Reflector, this is precisely what’s displayed.

If this were the sum total of F#’s programming capabilities, the language wouldn’t merit much in the way of interest-some, mind you, because these functions are exposed as static methods on a namespace defined to be the same as the file name (so, for example, the file1.exe assembly exports methods called “File1::xtimesy” in the above example), and are thus usable from C#. But F# can also “do objects”, as it turns out.

Classes in F#

Building a class in F# is actually fairly straightforward, with some interesting caveats and differences from traditional C# classes:

type Person(firstName: string, lastName: string,
                  age: int) =
    static member Nobody = Person("", "", 0)
    member this.FirstName = firstName
    member this.LastName = lastName
    member this.Age = age
    override this.ToString() : string =
        System.String.Format("[Person {0} {1}
            ({2} years old)]",
            firstName, lastName, age)
    
let p = Person("Ted", "Neward", 37)
    
printfn "Creating new Person %A" p

The Person type here is certainly not complicated by any means, but several F# syntactic constructs make the class shorter and more succinct.

For example, consider the Person constructor. In C#, this would be a separate method whose name must match the type and have no return type, and the body of which is often taking parameters and storing them directly into fields of the same or similar name. This pattern is so common that in F# you define a primary constructor on the type definition line itself (“type Person”, above) and the implementation naturally defines fields of those names and types, as well as generate the logic to store the constructor parameters into those fields.

Or, as another case of F#’s succinctness, consider how type inferencing makes the definition of the FirstName, LastName, and Age properties: no type information is needed there, since it can all be inferred from the definition around the fields (firstName, lastName, and age, respectively) used in the property definition.

Similarly, to create a new instance of the Person type, F# client code simply calls the Person constructor as a direct method call, rather than keying off of the “new” keyword as in C#. Again, a simple syntactic change that reduces code verbosity, albeit a single keyword, helps make the language more readable overall.

Also, fairly obviously, F# uses no “Begin/End” or curly-brace characters to delimit the start and end of the type declaration; this is also true of various looping and other nesting constructs, such as the “if” expression shown later. In order to avoid any such obvious delimiter, F# borrows a trick from Python, that of significant whitespace: in an F# program, the language determines whether a block of code is part of the nested block or the outer block based on its indentation level. Thus, in the definition of “ToString” above, the implementation of the method must be one indentation level “deeper” than the indentation level at which the other member definitions sit.

This aspect of F# is one of its more controversial features (just as it is with Python), but for the most part, it fades into the background during coding. However, one thing that may bite the budding F# programmer shortly after installation is that the F# integration in Visual Studio will complain if the editor is set to use tabs instead of spaces for indentation, so make sure to clear that option in the Tools | Options dialog under the TextEditor | F# node.

Matchmaker, Matchmaker, Bind Me a Match

One of the most powerful features of a functional language like F# is that of pattern-matching, in which a value can be “matched” against a series of potential targets, not unlike how a switch/case works in C#. However, pattern-matching is so much more powerful than switch/case, because not only can it match values against the determinant, but it can also match against the type of the determinant, and extract values out of the determinant and into local variables for further process, all in one step.

Pattern-matching is so much more powerful than switch/case, because not only can it match values against the determinant, but it can also match against the type of the determinant, and extract values out of the determinant and into local variables for further process, all in one step.

An example suffices. First, create an array of the above Person type; this collection will be a collection of Persons, over which the code will iterate across and take various actions based on the contents therein:

let people =
    [| Person("Ted", "Neward", 37);
       Person("Amanda", "Laucher", 27);
       Person("Matthew", "Podwysocki", 35);
       Person("Rachel", "Appel", 35);
       Person.Nobody;
       Person("Scott", "Allen", 38);
       Person("Luke", "Hoban", 18); |]

The array syntax in F# is a bit different from C# or VB, in that the elements are semicolon-separated, and the array contents are denoted using the “[|” and “|]” character pairings.

Next, to iterate across the array (or any other collection in F#, which will more commonly be a list or sequence type), a for comprehension is used:

for per in people do
    printf "Matching %A: " per

On the surface, it looks very much like a traditional C# or VB “for” or “For Each” iteration construct, but internally the F# code works slightly differently. For now, the differences are immaterial.

Finally, the actual pattern match takes place, in which the current element, per, is matched against a series of potential candidates, and the first match executes the associated code block (on the other side of the arrow):

for per in people do
    printf "Matching %A: " per
    match per.FirstName with
    | "Ted" -> printfn "Hey, Ted!"
    | "Amanda" -> printfn "Hey, Amanda!"
    | x -> printfn "Hey, %s!" x

The pattern match begins by extracting the FirstName value out of the property on “per”, and matching that against the first candidate, which in this case is the constant value “Ted”. If it finds it, it uses the F# library function “printfn” (which is essentially a wrapper around System.Console.WriteLine) to print a message to the console. Ditto for “Amanda”, but in the third case, it takes whatever value is in “per.FirstName” and binds it to the local identifier “x”, and (in this case) prints it to the console.

Although it’s not obvious from this example, a match construct, like most of F#’s syntax, returns a value. In this case, the value is unit, which is the functional equivalent of C#’s void (or VB’s Nothing). This means that every branch of the match must return unit, which fortunately “printfn” does. There’s no prohibition against returning a different value, by the way; it’s just that in this (admittedly overly simple) example, the only thing that needs to be done is to print to the console, which returns unit.

You can also use pattern matching to match against more than one value at a time. Though to make this next example work the F# language will require a little bit of help, in the form of an active pattern construct, essentially a conversion function that can take a Person and break it up into constituent parts for easier matching:

let (|ParsePerson|) (p:Person) =
    if p.Equals(Person.Nobody) then
        (null, null, 0)
    else
        (p.FirstName, p.LastName, p.Age)
    
for per in people do
    printf "Matching %A: " per
    match per with
    | ParsePerson (_, _, 0) ->
        printfn "You're Nobody"
    | ParsePerson ("Ted", _, _) ->
        printfn "Hi, Ted!"
    | ParsePerson ("Amanda", _, _) ->
        printfn "Hi, Amanda"
    | ParsePerson (fn, ln, a) when a > 30 ->
        printfn "Hey, %s, ya old geezer!" fn
    | ParsePerson (fn, ln, a) when a < 30 ->
        printfn "Hey, Kid %s, shaving yet?" ln
    | _ -> printfn "No idea who (or what) you are"

The “ParsePerson” construct, above, is the conversion function, taking an instance of Person and returning in its place a three-part tuple consisting of the Person’s FirstName, LastName, and Age property values. Formally, F# calls this tuple type a type of “string * string * int”, and it is what the pattern-match construct will match against.

In the first case, the “_” character matches against any possible value, so any Person with an Age of 0 will successfully match here, regardless of first or last name (which are thrown away). The second case matches when the first value in the tuple is equal to the string “Ted”, and ditto for the third, “Amanda”. The fourth, however, binds each of the three values in the tuple to individual identifiers (“fn”, “ln”, and “a”), but only when the “a” value is over 30. The fifth does the same, but again, only when the “a” value is under 30. And, finally, since there are still a few potential cases that could slip through the cracks (such as when a is exactly equal to 30-what then?), F# requires a wildcard match at the very end; think of this as the “default” clause in a traditional case/switch.

Conclusion

There is obviously much more to be said about the F# language, as it is every bit as rich and as powerful as the C# and Visual Basic languages that now call F# brother inside of Visual Studio. Fortunately, F# ships with a fairly extensive (if underdocumented) set of sample code, for the F# programmer willing to do a little spelunking around in the F# installation directory. F# resources are steadily growing, both in scope and availability. Currently, you can find the language’s best language reference in the book Expert F# (Syme, Granicz, and Cisternio, APress, 2008), written by the language author himself (Don Syme). Other resources include theHubFS, a developer portal dedicated to F# programmers. And, of course, as F# nears its official release date, you can expect more resources within MSDN documentation and the Web site.

In the meantime, take a few moments to exercise the F# language, and see how thinking functionally can change the way you think about programming. If nothing else, it’ll be a nice break from all those other dis-functional languages, like C#... or Visual Basic… C++… HTML… Java…

Don’t mind me, I’ll just be going now.