An introduction to F#: Part 1

Posted on Updated on

A few days ago I ran an introduction to F# course for colleagues at work. The idea of the course was to explain the basics of F# including syntax, programming style and the FSI window, as well as to get people excited. I didn’t correctly judge how long the presentation would take (people were asking lots of questions as I went, which is good!), so I ended up splitting it up into two parts. Here I am publishing a rough written copy of the presentation, compiled from my notes that I worked from as I talked, for you to peruse. It’s somewhat rough, but for those who were there it should serve as a reminder. Next time we will talk through some worked examples of Fizzbuzz & fizzbuzzbaz, we will cover types (classes, structs, interfaces, enums, records, units of measure and discriminated unions). We will also go through some application design, such as: MVC, DDD, CQRS, WTFBBQ.

Introduction to F#

What is F#?

It is a strongly typed, multi-paradigm .NET programming language encompassing functional, imperative and object-oriented programming techniques. Although you may have heard that is is ideally suited for number crunching and mathematical computations (and, indeed, it is very good at those) it is in fact a general purpose programming language and can do everything C# can do, and more.

Being .NET you can continue to use all the libraries you’re familiar with, such as NHibernate, Xunit etc.

  • Open source, owned by F# Foundation.
  • Resources: F# for fun and profit, F# MSDN, F# Foundation
  • Pluralsight courses such as Mark Seeman’s A Functional Architecture in F# and Functional Data Structures

The FSI window

The FSI (F Sharp Interactive) window is a window available in all copies of Visual Studio that enables you to load and run arbitrary snippets of F#. You can either type into the window directly or right-click in your code in VS and select “Run in interactive”.

Values and functions

  • Defining values: “Binding a name to a value”
    let x = 5
  • Strongly typed + type inference
  • Types can be explicitly stated. “Type annotations”
    let x : int = 5
  • Defining functions
    let square x = x * x
  • Notice how everything is an expression, even blocks of code. No ‘return’.
  • Type inference *can look ahead* to see how a name is used
  • let printString s = printfn "%s" s

    Unit ~= void, but has a value

    ()

    and is a proper type, so List<Unit> is allowed, where List<void> is not.

  • Important to learn how to read function signatures, e.g.
    int -> int

    is equivalent to

    Func<int, int>
  • Changing how
    x

    is used will change the type of

    x

    and therefore the signature of

    f
  • let f x = x + " world"

    –>

    string -> string
  • Type annotations rarely used
  • How does type inference deal with
    let f x = x

    ? What type is x?

  • Call functions with space
    let message = f "Hello"
  • Functions take exactly one value and return exactly one value.
  • Multiple arguments:
    • Data structures e.g. classes, tuples
      let coords = 4, 5

      discuss next

    • Currying, discuss later

Data structures and patterns

  • Binding can make use of patterns to bind names to values, “destructuring” / “substructuring”
  • Syntax for destructing is same as used for constructing
  • Tuples
    let coords = 4, 5

    and

    let x, y = coords
  • Can do
    let x, y = 4, 5

    Optimised away.

  • Can be thought of as ad-hoc data structures
  • Lists:
    • []

      empty lists

    • [item1; item1]

      exact number of items. Note the semicolon; commas are for tuples only

    • item1 :: item2 :: rest

      at least n items (in this case at least two)

    • More to come after we discuss types
  • Can nest patterns indefinitely, e.g.
    (x, y, z) :: item2 :: rest
  • Can use
    as
    to name higher level patterns
    let (x, y) as coords = ...
  • Some patterns are complete. e.g.
    let x, y =
    matches all
    int * int

    tuples

  • Incomplete patterns = compiler warning
    let x, 1 = coords
  • Patterns can be tested against in
    match

    expressions

  • Like switch but based on patterns: “Pattern matching”
  • Primary form of branching in F#
  • Example, with explanation of type inference:
  • let rec sumInts list =
    match list with
    | [] -> 0
    | head :: tail ->
    head + sumInts tail
    
  • Patterns can be used in function definitions too:
    let printCoords (x, y) = ...

    this looks a lot like a function that take multiple arguments, but in fact it is one argument that is a tuple.

Currying

    • Functions can “take multiple arguments” by either taking a data structure or…
      • let add x y = x + y
    • Important: read function signature:
      int -> int -> int

      . Explain.

    • Functions are closures.
    • add

      is a function that takes an

      x

      and returns a function that takes a

      y

      (and has the value of

      x
       embedded) and returns an int.

 

  • This is the preferred method (but it’s up to you). Why? Partial application!
    • Remember: functions only take one argument.
      add

      takes an int. So what do I get if I call

      add 1

      ?

    • What is the signature of
      sth

      in

      let sth = add 1

      ? –>

      int -> int

      –>

      let inc = add 1
    • Any language that has closures also supports currying, E.g. Javascript
      var add = function (x){
      return function (y) {
      return x + y;
      }
      }var nine = add(4)(5); // => 9
      var inc = add(1);
      var six = inc(5) // => 6
      
  • Why don’t people curry in other languages, such as Javascript? Syntax makes it a pain

 

Control flows

  • If statements
  • for loops and comprehensions [], [||], seq, range, yield, yield!
  • Recursion

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 )

Facebook photo

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

Connecting to %s