Book Image

Mastering F#

By : Alfonso García-Caro Núñez, Suhaib Fahad
Book Image

Mastering F#

By: Alfonso García-Caro Núñez, Suhaib Fahad

Overview of this book

F# is a multi-paradigm programming language that encompasses object-oriented, imperative, and functional programming language properties. Now adopted in a wide range of application areas and is supported both by industry-leading companies who provide professional tools and by an active open community, F# is rapidly gaining popularity as it emerges in digital music advertising, creating music-focused ads for Spotify, Pandora, Shazam, and anywhere on the web. This book will guide you through the basics and will then help you master F#. The book starts by explaining how to use F# with Visual Studio, file ordering, and the differences between F# and C# in terms of usage. It moves on to explain the functional core of F# such as data types, type declarations, immutability, strong type interference, pattern matching, records, F# data structures, sequence expressions, and lazy evaluation. Next, the book takes you through imperative and asynchronous programming, F# type providers, applications, and testing in F#. Finally, we look into using F# with distributed programming and using F# as a suitable language for data science. In short, this book will help you learn F# for real-world applications and increase your productivity with functional programming.
Table of Contents (16 chapters)

Key features of F#


The following are some points that Distinguish the F# language from other .NET languages:

  • F# is a functional first language, which means that functions are treated as first-class citizens, but it also provides ways to work with other paradigms, such as object-oriented programming (OOP) (as in C#).
  • Unlike other languages, such as C#, which mixes expressions (language constructs returning a value) and statements (constructs that don't return a value), F# is an expression-based language. You can think of every syntax construct in F# as a small function.
  • F# is a strongly-typed language, meaning that the type of every expression in the program is determined at compile time. This allows the compiler to make verifications in our code and enables great tooling support, such as autocompletion, refactoring, and so on.
  • Additionally, F# has a very strong type inference mechanism to infer types for the expressions in a program. This removes much of the verbosity usually associated with strongly-typed languages.
  • The .NET generics' type system is baked into the core of F#. For example, the programmer doesn't have to specify the functions to be generic; if the F# type system infers the variables can be generic (provided it is implemented that way), the function becomes generic. This makes it easier to write polymorphic code, that is, functions that can be reused with different types.
  • F# has a module system that allows data structures to be specified and defined abstractly. Unlike C# namespaces, F# modules can contain functions that help you separate data (types) from logic (functions in modules).
  • F# implements a pattern matching mechanism, which allows controlling conditions based upon structural similarities; whereas, other languages only allow value matching as in IF...ELSE statements in C#.

Functional and imperative languages

Imperative languages usually modify the state of a variable for most operations. This makes it more difficult to reason about our program, particularly when different parts of our code change values that are globally accessible. When a piece of code modifies a value outside its scope, we talk about side-effects (this may also include other state modifications, such as file or console operations). OOP tries to tame side-effects by encapsulating state. However, this is not always a complete solution, as objects often develop tight and complex dependencies with each other that are still difficult to reason with.

Functional languages solve this problem using pure functions. Pure functions are closer to the mathematical ideal of functions, in the sense that they don't have side-effects (don't change state outside their scope) and always produce the same output given the same input. Pure functions are easier to refactor and reason with because their output is predictable, and can be used as building blocks to write large programs with different techniques of function composition.

F#, as described, is a functional-first language, but the language can also deal with unavoidable side-effects such as file or logging operations.

To compare F# with a more imperative language, we can take the example of a Fibonacci sequence generator, as follows:

public static int Fibonacci(int n)
{
    int a = 0;
    int b = 1;
    // In N steps compute Fibonacci sequence  iteratively.
    for (int i = 0; i < n; i++)
        {
            int temp = a;
            a = b;
            b = temp + b;
        }
            return a;
}

let rec fib n =
if n < 2
then 1
else fib (n - 2) + fib (n - 1)

Note

For illustration purposes, C# in procedural style is used. It is also capable of more functional implementations, such as Language Integrated Query (LINQ). Also, performance is not taken into consideration.

In an imperative language, the algorithm is normally implemented as a loop, and progress is made by modifying the state of the variables used in the loop.

In F#, the Fibonacci sequence is implemented using recursion. The let keyword, which defines the function, and the rec keyword, which specifies the function, can be called recursively. Using recursion, we are parameterizing the state (we will pass the updated values as parameters to the next call) so we do not need to use mutable variables.

However, please note that programs exclusively using a functional style can have performance problems. In this book, we will take an intermediate approach of using imperative code when necessary.