F# is the new kid on the block in terms of .NET languages. Currently in CTP form, it will be one of the .NET languages proper with the release of Visual Studio 2010 and the .NET Framework 4.0.
What makes F# different is its focus on being a functional language: F# is all about writing a program that indicates what you want to do, not how you want to do it (as imperative languages do). Functional languages in general have found favor in scientific and academic applications; however, they are by no means restricted to that domain. F# is actually a multi-paradigm language, meaning you can include imperative and object-oriented programming concepts as well, which bodes well for its adoption in more mainstream business applications.
There are a number of functional programming languages out there now, including Haskell, Eiffel, Scheme, and OCaml (with which F# shares its core language). One that you’re probably familiar with is SQL (Structured Query Language). Think about it, when you issue a SQL SELECT statement, you’re essentially expressing what you want, and how you get it is often a black-box operation carried out through the backend database’s query processor and optimization engine. LINQ (Language Integrated Query), which was added to the .NET Framework 3.5, similarly incorporates functional programming ideals.
One of the quickest ways to get started with F# is via F# Interactive, a Read-Evaluate-Print-Loop (REPL) tool for executing F# code. F# Interactive is part of the CTP download and can be run as a command line interface or from within Visual Studio (from the View->Other Windows menu).
Some of the core features (well, the ones I found exceptionally cool) of F# include
- type inference: F# is a strongly-typed language; however, data types don’t need to be specified explicitly, since they can be inferred at compilation time. For example, below
xis set to an integer and
yto a string; note the error that occurs when trying to set
zto a concatenation of the two. [The double-semicolon is used as a statement terminator here].
- immutability: One of the hallmarks of functional languages is the avoidance of state and mutable data. Immutable values have benefits in that they can actually prevent certain types of bugs, and they are inherently thread-safe, making code much easier to parallelize.
Given the multi-paradigm nature of F#, you can, however, use mutable variables (via the
mutablekeyword) as the snippet below shows.
Another way to handle mutable values is via reference variables, which create a pointer to memory on the heap that you can then modify via the := operator, for example:
- tuples: Tuples are an ordered collection of values that you can treat as a unit without having to define a new type. In the sample below:
- The first line defines a tuple,
myName, consisting of two string values, here my first and last name.
- The second line defines a function that takes one argument, a 2-tuple. Here,
lastrefer to the two values within the tuple (a function declared with two arguments would not use parentheses nor a comma separator).
- The final line prints out the result of the function, namely a string with the first and last names of the tuple concatenated with a space separator.
- first-order function passing: First-order functions (namely functions whose parameters and return value are NOT functions themselves) are also known as lambda expressions. When coupled with the F#
Listcollection type, for example, you can do some nifty things like find the palindromes in a list of strings with a single line of code!
- Pipe and forward: In the above snippet, note the use of the pipe-and-forward operator (|>) which is a shortcut for passing arguments to methods. In that sample, we could have done without it (and just called
List.filter(…) strList), but it enables you to conveniently string together a series of methods that successively transform the input. For instance, here we extend that snippet to get the number of palindromes in the list:
- white space: One interesting facet of F# that takes a little getting used to is the notion of significant white-space. With conditional statements, for instance, there is no equivalent of an “END IF” or curly braces to delimit statement blocks. In F#, the scope of the statement is determined by the indentation. Note the difference in output in the following:
I’ve really just scratched the surface here, and since F# is a .NET language, you’ll be able to leverage the classes you’re accustomed to in C# and VB.NET (note, we used
System.String.ToCharArray()in the palindrome sample above). There’s support for conditionals and loops, which themselves are functions, as well as exception handling via syntax similar to try-catch-finally. One particularly powerful feature I didn’t touch upon above is the
match expression which is commonly used with yet another language concept known as discriminated unions. In fact, as you get more familiar with the functional programming style, you’ll find that pattern matching (via
match) and recursion will take the place of many instances where you’d rely on if’s and for loops in imperative languages.
For a deeper dive into F#, check out these great on-line F# resources: