Why F#

F# is a functional programming language developed by Microsoft Research based on decades of experience gained through the ML / Ocaml family of functional programming languages. F# is implemented on top of the .NET common language runtime (CLR) and can interact with software developed in C# and VB.NET.

The F# programming language is an excellent combination of the industry-proven .NET framework with the well-researched ML-familiy of programming languages. Below are some examples of language features which separate F# from other state-of-the-art programming languages.

Functions as first class values

Functions are first class values in F#. This means, that you may pass a function as an argument to other functions.

> let f = fun i j -> i + j;;

val f : int -> int -> int

> List.map (f 15) [1; 2; 3];;
val it : int list = [16; 17; 18]

Static Type System

The F# static type system enforced by the compiler ensures that a lot of mistakes are already detected during compile-time which may only be detected during runtime in dynamically typed languages.

# test.py python source
def f():
  a = 1
  s = "abc"
  a + s

When loading the above module the python interpreter does not give an error. Only when the function f is invoked an exception is thrown, because adding a string to an integer is not supported.

~> python
Python 2.6.5 (r265:79063, Jul  5 2010, 11:47:21)
[GCC 4.5.0 20100604 [gcc-4_5-branch revision 160292]] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import test
>>> test.f()
Traceback (most recent call last):
 File "", line 1, in
 File "test.py", line 4, in f
 a+s
TypeError: unsupported operand type(s) for +: 'int' and 'str'
>>>

Type Inference

F# is a statically typed language, however, due to the type inference capability of the F# compiler most type declarations can be omitted as they are inferred by the compiler. Type inference combines the compact code of dynamically typed languages with the type safety and execution speed of statically typed languages.

> let a = 1;;

val a : int = 1

> let add1 n = n+1;;

val add1 : int -> int

Variant Types

F# is able to detect some type of mistakes during compile-time which are not even detected by todays statically typed languages. For example variant types can be tested for exhaustiveness. The following Java source will compile, but will silently fail during execution when invoked with the argument ‘Choice4’.

// The missing test for Choice4 is only detected during runtime public class ChoiceClass { enum Choice { Choice1, Choice2, Choice3, Choice4 } public void select(Choice ch) {  switch(ch) {  case Choice1:  System.out.println("Choice1 selected");  break;  case Choice2:  System.out.println("Choice2 selected");  break;  case Choice3:  System.out.println("Choice3 selected");  break;  } } }

The corresponding F# source will raise a warning already during compile time.

> type Choice = Choice1 | Choice2 | Choice3 | Choice4;;

type Choice =
 | Choice1
 | Choice2
 | Choice3
 | Choice4

> let f ch = match ch with         
-                  | Choice1 -> "1"
-                  | Choice2 -> "2"
-                  | Choice3 -> "3" ;;

 let f ch = match ch with
 -----------------^^

~/stdin(19,18): warning FS0025: Incomplete pattern
matches on this expression. For example, the value 'Choice4'
may indicate a case not covered by the pattern(s).

val f : Choice -> string

>

The benefit of exhaustiveness tests is especially helpful when refactoring or changing code as the compiler will point you to all places where code needs to handle the changed type.

Meta-Programming

F# supports programming on the meta-level through quotations. Quotations are code put between special tokens ‘<@’ and ‘@>’ and are compiled into a data structure for later evaluation by user code, similar to Lisp makro’s.

> let one = <@ 1 @>;;
val one : Quotations.Expr<int> = Value (1)

> <@ let f x = x + 1 in f 1 @>;;
val it : Expr<int> =  
  Let (f,    
    Lambda (x,            
            Call (None, Int32 op_Addition[Int32,Int32,Int32](Int32, Int32),                  
                  [x, Value (1)])), Application (f, Value (1)))    
    {CustomAttributes = [NewTuple (Value ("DebugRange"),          
       NewTuple (Value ("stdin"), Value (5), Value (7), 
                 Value (5), Value (10)))]; Raw = ...; Type = System.Int32;}

Quotations may be used to invoke custom code generators to transform code into special representations, e.g. JavaScript for client side code in web applications.

Multi-threading support

Due to the increasing number of CPU cores in todays computers, it is becoming more and more important to allow implementation of algorithms in a parallel style to scale to multi-core architectures. F# provides an extensive library and language features to do so without unnecessary boilerplate code.

> let f i = async { return i*i }                                        
- let l = [|1..1000|]
- let r = l |> Array.map f |> Async.Parallel |> Async.RunSynchronously;;

val f : int -> Async
val l : int [] =
 [|1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 11; 12; 13; 14; 15; 16; 17; 18; 19; 20; 21;
 22; 23; 24; 25; 26; 27; 28; 29; 30; 31; 32; 33; 34; 35; 36; 37; 38; 39; 40;
 41; 42; 43; 44; 45; 46; 47; 48; 49; 50; 51; 52; 53; 54; 55; 56; 57; 58; 59;
 60; 61; 62; 63; 64; 65; 66; 67; 68; 69; 70; 71; 72; 73; 74; 75; 76; 77; 78;
 79; 80; 81; 82; 83; 84; 85; 86; 87; 88; 89; 90; 91; 92; 93; 94; 95; 96; 97;
 98; 99; 100; ...|]
val r : int [] =
 [|1; 4; 9; 16; 25; 36; 49; 64; 81; 100; 121; 144; 169; 196; 225; 256; 289;
 324; 361; 400; 441; 484; 529; 576; 625; 676; 729; 784; 841; 900; 961; 1024;
 1089; 1156; 1225; 1296; 1369; 1444; 1521; 1600; 1681; 1764; 1849; 1936;
 2025; 2116; 2209; 2304; 2401; 2500; 2601; 2704; 2809; 2916; 3025; 3136;
 3249; 3364; 3481; 3600; 3721; 3844; 3969; 4096; 4225; 4356; 4489; 4624;
 4761; 4900; 5041; 5184; 5329; 5476; 5625; 5776; 5929; 6084; 6241; 6400;
 6561; 6724; 6889; 7056; 7225; 7396; 7569; 7744; 7921; 8100; 8281; 8464;
 8649; 8836; 9025; 9216; 9409; 9604; 9801; 10000; ...|]

Multi-threading support in F# may be especially pleasing to Ocaml-users who currently cannot develop multi-threaded applications in Ocaml.

Rich Library

F# is implemented on top of the .NET framework, all libraries and modules available as part of the .NET runtime system are available in F# without additional glue code. This includes code written in C# or VB.NET.

The Base Class Library (BCL) includes:

  • System – base types for boolean, string, exceptions, arrays
  • System.Collections – lists, queues, stacks, hashtables, dictionaries, generics
  • System.Diagnostics – event logging, performance counters, tracing
  • System.Globalization – culture related information: language, calendar, currency
  • System.IO – file IO, streams, file system access
  • System.Net – network protocols such as HTTP, FTP, SMTP, SSL
  • System.Reflection – access to the CLR type system, create types dynamically
  • System.Runtime – access to the Common Language Runtime (CLR)
  • System.Security – access to CLR security system and cryptography
  • System.Text – text encoding, regular expressions
  • System.Threading – multi threading and synchronization
  • System.CodeDom – create code dynamically
  • System.ComponentModel – component interface and marshalling
  • System.Configuration – configuration files
  • System.Data – access to external data and services, e.g. SQL
  • System.Deployment – Microsoft ClickOnce software deployment
  • System.DirectoryServices – Microsoft Active Directory support
  • System.Drawing – 2D text and graphics, imaging and printing
  • System.EnterpriseServices – COM+ access
  • System.Linq – Language Integrated Query, SQL query language extensions
  • System.Linq.Expressions – code as expression tree data structure
  • System.Management – system information
  • System.Media – sound
  • System.Messaging – network messaging and transactions
  • System.Resources – application internationalization
  • System.ServiceProcess – Windows services
  • System.Timers – timers, timed events
  • System.Transactions – transactions for e.g. safe concurrent database access
  • System.Web – Web 2.0 services
  • System.Windows.Forms – Windows Forms GUI
  • System.Xml – reading, writing, processing XML data

The Mono implementation provides already most features of the .NET Framework Version 2.0 and Version 3.5, Version 4.0 is being worked on (read more here Mono Compatibility).

Light Syntax

The F# syntax uses space characters to identify code blocks similar to Python. Together with type inference this makes the F# source code extremely brief.

if a = 1 then
  printf "abc"
else
  printf "def"

F# is restricted to space characters for indentation to avoid problems when mixing tabulators and space characters (also a recommended practice in Python).

Linux support

Through the Mono project, the F# SDK tools can be used on other platforms than Microsoft Windows. Mono aims at full compatibility with .NET V 2.0, new .NET versions are being worked on. However, the .NET support for the Windows platform is still (and probably will remain) superior to other platforms.

Open Source

Believe it or not, F# is open source. Microsoft released F# into open source on 4th of November 2010. This will definitely help the adoption of F# by other major users as it cannot be dominated by Microsoft alone.

2 Responses to Why F#

  1. TechNeilogy says:

    Good summary; I’m continually looking for ways to explain F# to other programmers.

    BTW: Nice blog overall, you’ve got things organized very well.

  2. Pingback: “Why F#?” by F# Weekly | Sergey Tihon's Blog

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s