Benefits

If you are a long time C# or Java developer, you may be wondering why would be worth learning another language. Or you already heard about functional and want to see if F# is a good spot. Regardless, F# has some great benefits under several areas that might catch your attention.

1. Conciseness. Write less code, avoid unecessary things. You don't need to write so much code just to meets the standard of the language, or the compiler. You don't see so much "noise" when coding, like curly bracktes and semicolons. Most of them are not necessary or optional.

// Type inference: F# deduces types automatically
// We will see later how it works: F# still is a static typed language!
let one = 1
let joe = "Joe"
// Functions: no curly braces, semicolons or parentheses
let sum a b = a + b
let five = sum 2 3
// If you need a context, they are separated by identation
// The last computed value (a + b) is always the return value
let sumAndLog a b =
printfn "Adding %d to %d" a b
a + b

2. Convenience. Common time consuming tasks are way easier and faster to do in F#. We can create complex type definitions, list processing, equality of complex objects, state machines and more in just a few lines. Functions are also treated as objects, so we can use them as arguments to other functions and get a whole new level of code reuse.

// Simple types can be defined in one line (or more, if you wish)
// This is a record type
type Person = { FirstName: string; LastName: string }
// Complex types can be created in few (if not one) lines
// This is a Discriminated Union, which uses Person and itself types to
// define a Employee entity: it can be a worker (in which case we have
// its Person definition attached to it), or a Manager of Employees
// (recursively reusing his own type)
type Employee =
| Worker of Person
| Manager of Employee list
// Obviously, type inference works for our new created types aswell!
let jdoe = { FirstName = "John"; LastName = "Doe" }
let worker = Worker jdoe
// Equality of many structures are already implemented by default
let person1 = { FirstName = "John"; LastName = "Doe" }
let person2 = { FirstName = "John"; LastName = "Doe" }
let person3 = { FirstName = "John"; LastName = "Arthur" }
printfn "person1 equals person2? %b" (person1 = person2) // true
printfn "person1 equals person3? %b" (person1 = person3) // false
// Working with lists is easy. Lets sum all numbers from 1 to 100
[1..100] |> List.sum |> printfn "Sum is %d"
// Operators are functions and can be used like them: first its name,
// and after it, its arguments - because they are not used by default
// in this form, we need to put their name in parentheses
// Here is an example of partial application: you can define a new
// function by calling an existent one, and passing less arguments -
// the remaining ones will be the arguments of our new function
let add2 = (+) 2 // adds 2 to a number
let times3 = (*) 3 // multiplies 3 to a number
// We can easily compose new functions from older ones
// For example, to create a function that adds 2 to a number and after it
// multiplies 3, just use the composition parameter
let add2times3 = add2 >> times3
let nine = add2times3 1 // (1 + 2) * 3

2. Correctness. F# type system is really powerful. It prevents many common errors, like null reference exceptions. It's relatively easy to encode business logic into type definition, so we enter into a state that our code does not allow objects which are in an invalid state. And it is done in design time, so we can't even write incorrect code. The compiler itself helps us maintaining our BL!

3. Completeness. As already said before, F# is a functional-first language. It suppports other styles which are not 100% pure functional, making it easier to interact with other technologies. Because it is designed to be a hybrid language, it works under the same CLI of C#: not only it can do virtually everything C# does, but also F# assemblies can be used by C# code and vice-versa. Every .NET CLI assembly is accessible to us, and we can use them whenever we need.

Syntax

Here is a quick recipe on how to use F# syntax. With this, newcomers can quickly get used to it. I am not using very detailed information, and do not worry if you don't understand everything yet. Future posts will explain better those features.

// Single line comment
(* Multi line comment
Line two of comment *)
// "let" keyword defines a value - immutable by default
let five = 5
let pi = 3.14
let name = "Ismael"
// Functions are also treated as values, so we define them
// by using "let" keyword too
let square n = n * n
let four = square 2
// As said before, multiline functions dont need semicolons or
// symbols to delimit their scope. Just use identation
// We also can have functions inside functions, closed to their
// scope, and use functions as parameters: List.filter applies
// a function that receives one element and decides if it should
// be added to a new, returned list
let evens list =
let isEven x = x % 2 = 0
list |> List.filter isEven
// Lists and list comprehensions
// Square brackets, separated by semicolons makes lists
let twoToFive = [2; 3; 4; 5]
// You can easily prepend or append values to create new lists
// by using the :: operator
// Lists are immutable by default, like other types
// So this is a new list created from 1 and twoToFive
let oneToFive = 1 :: twoToFive // [1; 2; 3; 4; 5]
// You can also connect lists to create new ones
// by using the @ operator
let zeroToFive = [0; 1] @ twoToFive
// Functions can be chained together in a easy readable way
// Imagine a function that receives a list of integers,
// apply square to them and then sum them all
// We could use List.sum and List.map to do it like we are used to
let sumOfSquaresTo100 =
// List.map creates a new list from an existing one, applying
// the function of the first parameter to each element of the
// list of the second parameter
let squares = List.map square [1..100]
// Now we sum our squares and return it
List.sum squares
// We could implement this in one line, using parenthesis to
// enclose the second parameter code to generate squares list
// Its important to understand the necessity of parenthesis:
// If we dont use them, List.sum will take List.map function
// definition as an argument, not the entire operation
// This is because we dont use semicolons to pass funciton
// parameters in F#
let betterSumOfSquaresTo100 =
List.sum (List.map square [1..100])
// Now there we have an even easier way to do it, and it becomes
// more read friendly. The "|>" operator takes a value in the left
// and applies as the last parameter of a function call
let evenBetterSumOfSquaresTo100 =
[1..100] |> List.map square |> List.sum
// You can also create anonymous function lambdas with "fun"
let sumOfSquaresTo100WithLambda =
[1..100] |> List.map (fun x -> x * x) |> List.sum
// Pattern matching
// Pattern matching is like a better switch/case statement
let stringAnalyser str =
match str with
| "a" -> printfn "str is a"
| "b" -> printfn "str is b"
| s when s.StartsWith("a") -> printfn "str starts with a"
| _ -> printfn "str is something else" // "_" matches everything
// Discriminated Unions represent choices
// We define choices with pipes
type Temp =
| DegreesC of float
| DegreesF of float
let temp = DegreesC 98.6 // A way to represent 98.6 Celsius
// We don't use null by default
// We use a special Discriminated Union for this: Option
// Already in FSharp.Core, don't need to implement this!
type Option<'a> =
| Some of 'a
| None
let presentValue = Some 12 // Option<int>
let missingValue = None
// Discriminated Unions should be read with pattern matching,
// And we need to treat all cases. We can't forget to treat null
// values this way!
let seeIfIsPresent value =
match value with
| Some i -> printfn "Value is present: %i" i
| None -> printfn "Value is missing!"
seeIfIsPresent presentValue // prints "Value is present: 12"
seeIfIsPresent missingValue // prints "Value is missing!"
// Printing values to console can be done by using
// printf and printfn - they work like Console.Write and
// Console.WriteLine, respectively
// They enforce type checking in string patterns
printfn "Printing an integer %d, a float %f and bool %b" 1 2.0 true
// %A receives anything. If it is an F# type, it does pretty
// printing (a list would print every element of it, for example)
// If it is not an F# type, it calls .ToString() method of the type
printfn "A sring %s and something generic %A" "hello" [1; 2; 3]
// We also have a function that works the same way for string
// formatting, like String.format - sprintf
let hello name = sprintf "Hello, %s" name

Next steps

Oh my, this was a considerable amount of sample code to a post. On the next series of posts, we will be talking a bit deeply about functions: the central element of the functional paradigm. If you are liking F# so far, keep trying it. Don't forget to see F# for fun and profit if you want to speed up your learning process.