Chart-tastic F# Goodness

Happy New Year everyone!

I hope the holiday season was full of beer, wine, grub and every other kind of delightful merriment imaginable. The bear is back and absolutely raring to go! So, in an attempt to be a little more diligent and focused, I’ll crack on with the list of goodies I wanted to cover; starting with a small post on F# charting capabilities.

If you read my previous posts on Future Decoded 2015 and F# you’ll know that I’ve built up a little bit of a soft spot for F# (again, just to reiterate, the Don Syme Future Decoded F# Breakout Session was excellent and is a must watch). To continue on my journey a little bit I wanted to move beyond syntax, basic data aggregation/manipulation and type providers to touch on data presentation; namely the F# charting assemblies specifically.

Here’s a quick guide on how to get started in Visual Studio:

Project Setup

To get started from Visual Studio you have a couple of choices; you can create a full blown F# Library Project (for a more in depth/permanent piece of code) or, within Visual Studio 2015 at least, you can simply create an F# script to be run in F# Interactive without the overhead of a Project. As I’ll be bringing the F# Charting Library into scope, using NuGet, a project makes more sense in this instance, but here are the steps on both should you feel nosey:

Create an F# Script

Go to the File > New menu within Visual Studio 2015 and select the File option (without a Solution or Project currently open). You can then simply select the F# Script File option to get rocking and rolling:

New F# Script File.

New F# Script File.

Create an F# Project

As per any other project you can simply navigate to File > New > Project and select the Visual F# templates. You’ve got options for creating Console Applications, Portable Libraries, Unit Test Applications, etc. From what I’ve seen, the Tutorial project is actually well worth a look, this can be used in conjunction with the tryfsharp website to grease the wheels if needed! For this project, the normal F# Class Library will suffice:

New F# Library.

New F# Library.

Once your project is created you can access and begin scripting using the .fsx file included in the project; no sweat so far!

Script.fsx File.

Script.fsx File.

As an aside, the F# Interactive window (where output is logged for an F# script file) can be accessed from the View > Other Windows > F# Interactive (Ctrl + Alt + F) option.

For those who want to hoover up more background knowledge, further information surrounding writing F# within Visual Studio can be found here:

Using Visual Studio to Write F# Programs

F# Charting Assemblies

We next have to ‘NuGet it up’ and bring some extra resources into scope. This can be done using the Tools > NuGet Package Manager > Manage NuGet Packages for Solution option and then searching for FSharp.Charting, followed by clicking install (see image below), or more simply via the Package Manager Console found under Tools > NuGet Package Manager > Package Manager Console and use the command ‘Install-Package FSharp.Charting’:

Nuget Package Manager F# Charting Search.

Nuget Package Manager F# Charting Search.

Install via Package Manager Console.

Install via Package Manager Console.

Further gubbins on how to install the FSharp Charting Library on other environments (and a link to the NuGet package we’ve utilised here for reference) can be found here:

F# Charting: Library for Data Visualisation
F# Charting (NuGet)

Once you’ve installed the package using either method we’re nearly ready to get charting.

At this point, to run the examples coming up, you’ll also need to:

  • Install the FSharp.Data NuGet package (using exactly the same process as detailed above). Command: ‘Install-Package FSharp.Data’.
  • Install the FSharp.Data.TypeProviders package (again, using the same process detailed above). Command: ‘Install-Package FSharp.Data.TypeProviders’.
  • Reference System.Drawing within your F# Project (using References > Right Click > Add Reference > Assemblies > Framework).

More information here:

FSharp.Data NuGet Package
FSharp.Data.TypeProviders NuGet Package

We’re fully set and ready to go, so on to the charting!

Line Chart

The plan here is to briefly demonstrate each type of chart in action. This first example will be a basic evolutionary piece showing an expansion from a bare bones chart into a more full example utilising some more complex constructor options and styling tweaks (nothing too meaty however!).

Within your .fsx script file you’ll need to begin with the following (highlight the lines and use Alt + Enter to run the code within F# Interactive. If you’re using ReSharper be aware that this keyboard shortcut may be mapped, so you might have to do some jigging!):

//Give F# Interactive awareness of the packages folder (it will allow easier loading/references of resources below)
#I "..\packages"

//Read, compile and run the FSharpt.Charting.fsx file (to access the functionality of FSharp.Charting.dll)
#load "FSharp.Charting.0.90.13\FSharp.Charting.fsx"

//Read in the FSharp.Data and FSharp.Data.TypeProviders assemblies (so we can make use of the HtmlProvider)
#r @"FSharp.Data.2.2.5\lib\net40\FSharp.Data.dll"
#r @"FSharp.Data.TypeProviders.0.0.1\lib\net40\FSharp.Data.TypeProviders.dll"

//Access namespaces as required by the examples. System for the 'Random' type and use of String.Format, FSharp.Data for the HtmlProvider, FSharp.Charting for what is says on the tin
//and System.Drawing for chart styling elements
open System
open FSharp.Data
open FSharp.Charting
open System.Drawing

//Write code to utilise FSharp.Charting
//...

You will see dialogs matching the following thrown during this process, you’ll need to select ‘Enable’:

Type Provider Enable Dialog.

Type Provider Enable Dialog.

Now, some of these reference assemblies and opened namespaces are required for later examples; we’re just getting F# Interactive primed and ready so we don’t have to do any further work down the road. Here’s a quick rundown on the directives being used here:

  • #I: Specifies a search (hint) path so that F# Interactive can intelligently search for resources you reference.
  • #load: Reads, compiles and runs the specified resource.
  • #r: References an assembly directly.
  • open: Imports an assembly (like a C# ‘using’) ready for use in F# code.

In short, we add a search path using #I so F# Interactive can more easily find resources (in our packages directory) without the need to provide a full, absolute path. The #load directive reads, compiles and runs the FSharp.Charting.fsx file, which neatly references the FSharp.Charting assembly as well as the supporting System.Windows.Forms.DataVisualization assembly. A hop, skip and jump later, we can then reference assemblies (added by NuGet) in the packages directory in a more simple manner using #r (you could just as easily references dlls from the bin folder, I need to do some further reading on this to get a feeling for best practice). Lastly, open (begin ‘using’) namespaces linked to these resources as required, boom!

Here’s a wonderful little list detailing the ins and outs of fsi.exe for those who want to delve further.

What can we do with all of this magic…make a chart of course; starting with charting 101, the line chart (run this in F# Interactive as before by highlighting the code and using Alt + Enter):

//Define an array of resting heart rate values
let restingHeartRateValues = [69; 74; 76; 71; 68; 65; 64; 79; 80; 75; 72; 65; 63; 62; 59; 65; 80; 61; 59]

//Produce a line chart to visualise this data
Chart.Line(restingHeartRateValues)
Basic Resting Heart Rate Line Chart.

Basic Resting Heart Rate Line Chart.

That’s it, first chart down! The resting heart rate values array (I’m still getting used to semi-colon separated values!) is used as the ‘data’ input for a call to Chart.Line. The next few code snippets illustrate some alternative syntax for this operation. You can use the ‘|>’ syntax if you just wish to produce a chart with no bells and whistles. For extra levels of shininess (i.e. styling the chart) you can add additional method calls as required. Let’s go through some examples:

//Inline the array directly into the call to Chart.Line
Chart.Line([69; 74; 76; 71; 68; 65; 64; 79; 80; 75; 72; 65; 63; 62; 59; 65; 80; 61; 59])

//Or, alternatively, calling the basic Chart.Line constructor using |> syntax
[69; 74; 76; 71; 68; 65; 64; 79; 80; 75; 72; 65; 63; 62; 59; 65; 80; 61; 59]
|> Chart.Line
//Define an array of resting heart rate values
let restingHeartRateValues = [69; 74; 76; 71; 68; 65; 64; 79; 80; 75; 72; 65; 63; 62; 59; 65; 80; 61; 59]

//Produce a line chart to visualise this data (with a Name, Title and labels for the X and Y axis)
Chart.Line(restingHeartRateValues, Name = "Resting Heart Rate Chart", Title = "Resting Heart Rate by Day", XTitle = "Days", YTitle = "Heart Rate (BPM)")
Styled Resting Heart Rate Line Chart.

Styled Resting Heart Rate Line Chart.

Here, we called some additional constructor arguments of Chart.Line (by name) to name the chart (this appears in the chart window header), give the chart a title (which appears within the chart window, normally overlaying the chart), in addition to naming the chart axis labels.

//Define an array of resting heart rate values
let restingHeartRateValues = [69; 74; 76; 71; 68; 65; 64; 79; 80; 75; 72; 65; 63; 62; 59; 65; 80; 61; 59]

//Produce a line chart to visualise this data (with a Name, Title and labels for the X and Y axis)
Chart.Line(restingHeartRateValues, Name = "Resting Heart Rate Chart", Title = "Resting Heart Rate by Day", XTitle = "Days", YTitle = "Heart Rate (BPM)"
).WithYAxis(Min=55.0) //X Axis starts at 55
Styled Resting Heart Rate Line Chart (Axis Minimum Applied).

Styled Resting Heart Rate Line Chart (Axis Minimum Applied).

A slight extension to the above example, you can perform fine-tuning of each axis (you can control the label this way also) by calling WithYAxis or WithXAxis. In this case, I’m specifying a minimum value for the given axis to control how the chart is presented, all very fine and dandy. On to the next example we go.

//Define an array of resting heart rate values
let restingHeartRateValues = [69; 74; 76; 71; 68; 65; 64; 79; 80; 75; 72; 65; 63; 62; 59; 65; 80; 61; 59]

//Produce a line chart to visualise this data (with a Name, Title and labels for the X and Y axis)
Chart.Line(restingHeartRateValues, Name = "Resting Heart Rate Chart", Title = "Resting Heart Rate by Day", XTitle = "Days", YTitle = "Heart Rate (BPM)"
).WithYAxis(Min=55.0).With3D() //X Axis starts at 55 and with 3D (no extra 3D parameters specified, just as is)
Resting Heart Rate Line Chart (3D).

Resting Heart Rate Line Chart (3D).

In this final snippet I’ve added a call to With3D, because I couldn’t resist seeing what the chart looked like (what a sucker)!

Column Chart

Following up, a couple of iterations of a column chart can be found below (using a string * int list representing Kindle Charge data). This illustrates how to further style the X and Y axis definitions, as well as apply some styling to the chart in general.

//Produce some test data (representing a drop in Kindle charge by day)
let kindleChargeData = [
    "Monday", 100;
    "Tuesday", 91;
    "Wednesday", 87;
    "Thursday", 76;
    "Friday", 61;
    "Saturday", 55;
    "Sunday", 50;
]

//Produce a column chart (with some basic styling for the chart; covering colours and borders, etc.)
Chart.Column(kindleChargeData, Color=Color.Green, Name = "Kindle Charge Chart", Title = "Decrease in Kindle Charge by Day"
).WithXAxis(Title = "Day", TitleColor = Color.Purple
).WithYAxis(Title = "Charge", TitleColor = Color.Purple
).WithStyling(BorderColor = Color.DarkRed, BorderWidth = 3)
Kindle Charge by Day Column Chart (Basic).

Kindle Charge by Day Column Chart (Basic).

Same again, except for in 3D (with a limit of 100 ‘units’ placed on then Y axis):

//Produce some test data (representing a drop in Kindle charge by day)
let kindleChargeData = [
    "Monday", 100;
    "Tuesday", 91;
    "Wednesday", 87;
    "Thursday", 76;
    "Friday", 61;
    "Saturday", 55;
    "Sunday", 50;
]

//Produce a column chart (with some basic styling for the chart; covering colours and borders, etc.)
Chart.Column(kindleChargeData, Color=Color.Green, Name = "Kindle Charge Chart", Title = "Decrease in Kindle Charge by Day"
).WithXAxis(Title = "Day", TitleColor = Color.Purple
).WithYAxis(Title = "Charge", TitleColor = Color.Purple, Max = 100.00           //Apply a max here to prevent the chart from going beyond 100 on the Y axis
).WithStyling(BorderColor = Color.DarkRed, BorderWidth = 3
).With3D()                                                                      //Because I can't resist!!!
Kindle Charge by Day Column Chart (3D).

Kindle Charge by Day Column Chart (3D).

Just as a brief illustration, it is possible to combine individual charts into a unified entity using Chart.Combine as follows:

//A brief Chart.Combine example
Chart.Combine(
    [   
        Chart.Column([ 12 ], Labels = ["Amy"])
        Chart.Column([ 9 ], Labels = ["Buster"]) 
        Chart.Column([ 10 ], Labels = ["Dave"])
        Chart.Column([ 13 ], Labels = ["Shirley"])
        Chart.Column([ 7 ], Labels = ["Stephanie"])
        Chart.Column([ 11 ], Labels = ["Bob"])
    ]
    ).WithTitle(Text = "Tasks Completed"
    ).WithXAxis(Title = "No. of Tasks"
    ).WithYAxis(Max = 15.00)
Combined Column Chart.

Combined Column Chart.

Bar Chart

In this example we introduce the use of System.Random to produce a bar chart. After creating and binding ‘randomValue’ we utilise this in the construction of a for loop (which creates an integer list based on a number multiplied by a random number between a minimum and maximum limit). Drawing from previous learning, I’ve then mapped each value in this first list to an additional function (using List.map) to add another random value on to each initial integer. Lastly, we call Chart.Bar (the most basic form of the constructor) with the resultant data. Comments are inline to hopefully clarify how the code is working:

//Bind a new variable to use in RNG
let randomValue = new Random()

//Using alternative syntax this time as we are not calling a more complex Chart.Bar constructor (for styling purposes, etc.). Do some RNG and produce a bar chart
[ for i in 0..15 -> i * randomValue.Next(10, 20) ]      //For zero to fifteen, times i by a random value (between the minimum and maximum specified)
|> List.map(fun i -> i + randomValue.Next(1, 2))        //Map the result list to another function that adds another random value (between the minimum/maximum specified) to each initial value
|> Chart.Bar                                            //Produce the chart
Bar Chart Basic Example.

Bar Chart Basic Example.

Pie Chart

Moving on, we have a slightly more in depth example here using the HtmlProvider to scrape data off of a couple of Wiki pages for use in pie charts. The first example illustrates the breakdown of house types within Leigh in Surrey (I’ve never been but I’m sure it’s lovely. Leigh, here is your moment in the limelight!):

//Get a type denoting our pages structure (so we can strongly type against it), then retrieve live data by calling .Load
type WikiSurreyLeighStructure = HtmlProvider<"data_structure.html">
let liveDataTable = WikiSurreyLeighStructure.Load("https://en.wikipedia.org/wiki/Leigh,_Surrey").Tables.``Demography and housing 2``

//Prepare data scraped from the web page (details on the housing types in Leigh, Surrey)
let propertyTypeData = [
    String.Format("Detached ({0})", liveDataTable.Rows.[0].Detached), liveDataTable.Rows.[0].Detached
    String.Format("Semi-Detached ({0})", liveDataTable.Rows.[0].``Semi-detached``) , liveDataTable.Rows.[0].``Semi-detached``
    String.Format("Terraced ({0})", liveDataTable.Rows.[0].Terraced), liveDataTable.Rows.[0].Terraced 
    String.Format("Apartments ({0})", liveDataTable.Rows.[0].``Flats and apartments``), liveDataTable.Rows.[0].``Flats and apartments`` ]
 
//Display this data in a styled Pie Chart     
Chart.Pie(propertyTypeData
).WithTitle(Text = "Property Types in Leigh (Surrey)", FontSize = 26.00, FontStyle = FontStyle.Bold
).WithStyling(BorderColor = Color.BlueViolet, BorderWidth = 2
).With3D()
Leigh in Surrey Property Types Pie Chart.

Leigh in Surrey Property Types Pie Chart.

I’ve added the data_structure html document into the root of my project to provide F# with an understanding of the structure of the HTML page I want to interrogate (i.e. provide an entity which I can strongly type against). Using live data returned from hooking into this types .Load method, we are able to construct a simple data set (a string * int list), which we pass to Chart.Pie using some additional methods to create a ‘not all that great’ chart style! Apologies all, it turns out chart styling isn’t my forte 😉

Here’s on additional example showing the split (by millions) of males and females in the UK:

//Provide a type that outlines the page 'structure', so we can strongly type against it
type PopulationHtmlStructure = HtmlProvider<"data_structure_two.html">
 
//Retrieve live page data (and the relevant population html table)
let populationLiveDataPage = PopulationHtmlStructure.Load("https://en.wikipedia.org/wiki/Demography_of_the_United_Kingdom")
let populationLiveDataTable = populationLiveDataPage.Tables.``Age structure 2``
 
//Extract some data for Males and Females
let allPopulationData =
    [
        String.Format("Male ({0})", populationLiveDataTable.Rows.[4].Population), populationLiveDataTable.Rows.[4].Population;
        String.Format("Female ({0})", populationLiveDataTable.Rows.[4].Population2), populationLiveDataTable.Rows.[4].Population2;
    ]

//Simpler syntax, just call Chart.Pie with no extra bells and whistles
allPopulationData
|> Chart.Pie
 
//Produce a 3D pie chart, with some custom styling, based on this data
Chart.Pie(allPopulationData
).WithTitle(Text = "Population by Gender (Millions) - UK", FontName = "Verdana", FontSize = 26.00, FontStyle = FontStyle.Bold
).WithStyling(BorderColor = Color.AliceBlue, BorderWidth = 2
).With3D()
Population Gender Split UK Pie Chart  (Millions - Basic).

Population Gender Split UK Pie Chart (Millions – Basic).

Population Gender Split UK Pie Chart (Millions - 3D).

Population Gender Split UK Pie Chart (Millions – 3D).

Point Chart

Lastly, here is a randomly generated point chart, just to illustrate how this can be used:

//Declare and bind another 'random'
let anotherRandomValue = new Random()

//Create a basic point chart using the simpler |> syntax (denoting we are calling the basic Chart.Point constructor with no frills)
[for i in 0..500 -> anotherRandomValue.NextDouble(), anotherRandomValue.NextDouble()]
|> Chart.Point
Basic Point Chart.

Basic Point Chart.

//What does it look like in 3D. Hmmmm, not great!
Chart.Point([for i in 0..500 -> anotherRandomValue.NextDouble(), anotherRandomValue.NextDouble()]).With3D()
3D Point Chart.

3D Point Chart.

I hope this has provided a small insight into how you might use this in the wild. There are a fair few more chart types available so I’ll leave it up to you to dive in! Personally, I can see a window here to get hold of the JsonProvider and use this to access and manipulate data from my Fitbit. This is something I may touch on in the future so watch this space!

Thanks for reading through; full code listing below for convenience. Cheers and bye for now 🙂

Full Listing

//FSharp Charting (with HtmlProvider usage) - Full Scripting Example

//#region Setup

//Navigate to the directory containing the FSharp.Charting.fsx file
#I "..\packages\FSharp.Charting.0.90.13"

//Read, compile and run the FSharpt.Charting.fsx file (to access the functionality of FSharp.Charting.dll)
#load "FSharp.Charting.fsx"

//Read in the FSharp.Data and FSharp.Data.TypeProviders assemblies (so we can make use of the HtmlProvider)
#r @"..\packages\FSharp.Data.2.2.5\lib\net40\FSharp.Data.dll"
#r @"..\packages\FSharp.Data.TypeProviders.0.0.1\lib\net40\FSharp.Data.TypeProviders.dll"

//Access namespaces as required by the examples. System for the 'Random' type and use of String.Format, FSharp.Data for the HtmlProvider, FSharp.Charting for what is says on the tin
//and System.Drawing for chart styling elements
open System
open FSharp.Data
open FSharp.Charting
open System.Drawing

//#endregion Setup

//#region Line Chart

//Define an array of resting heart rate values
let restingHeartRateValues = [69; 74; 76; 71; 68; 65; 64; 79; 80; 75; 72; 65; 63; 62; 59; 65; 80; 61; 59]

//Produce a line chart to visualise this data (with a Name, Title and labels for the X and Y axis)
Chart.Line(restingHeartRateValues, Name = "Resting Heart Rate Chart", Title = "Resting Heart Rate by Days", XTitle = "Days", YTitle = "Heart Rate (BPM)"
).WithYAxis(Min=55.0).With3D() //X Axis starts at 55 and with 3D

//#endregion Line Chart

//#region Column Chart

//Produce some test data (representing a drop in Kindle charge by day)
let kindleChargeData = [
    "Monday", 100;
    "Tuesday", 
    "Wednesday", 87;
    "Thursday", 76;
    "Friday", 61;
    "Saturday", 55;
    "Sunday", 50;
]

//Produce a column chart (with some basic styling for the chart; covering colours and borders, etc.)
Chart.Column(kindleChargeData, Color=Color.Green, Name = "Kindle Charge Chart", Title = "Decrease in Kindle Charge by Day"
).WithXAxis(Title = "Day", TitleColor = Color.Purple
).WithYAxis(Title = "Charge", TitleColor = Color.Purple, Max = 100.00           //Apply a max here to prevent the chart from going beyond 100 on the Y axis
).WithStyling(BorderColor = Color.DarkRed, BorderWidth = 3
).With3D()                                                                      //Because I can't resist!!!

//A brief Chart.Combine example
Chart.Combine(
    [   
        Chart.Column([ 12 ], Labels = ["Amy"])
        Chart.Column([ 9 ], Labels = ["Buster"]) 
        Chart.Column([ 10 ], Labels = ["Dave"])
        Chart.Column([ 13 ], Labels = ["Shirley"])
        Chart.Column([ 7 ], Labels = ["Stephanie"])
        Chart.Column([ 11 ], Labels = ["Bob"])
    ]
    ).WithTitle(Text = "Tasks Completed"
    ).WithXAxis(Title = "No. of Tasks"
    ).WithYAxis(Max = 15.00)

//#endregion Column Chart

//#region Bar Chart

//Bind a new variable to use in RNG
let randomValue = new Random()

//Using alternative syntax this time as we are not calling a more complex Chart.Bar constructor (for styling purposes, etc.). Do some RNG and produce a bar chart
[ for i in 0..15 -> i * randomValue.Next(10, 20) ]      //For zero to fifteen, times i by a random value (between the minimum and maximum specified)
|> List.map(fun i -> i + randomValue.Next(1, 2))        //Map the result list to another function that adds another random value (between the minimum/maximum specified) to each initial value
|> Chart.Bar                                            //Produce the chart

//#endregion Bar Chart

//#region Pie Chart

//---------------PIE CHART EXAMPLE ONE---------------

//Get a type denoting our pages structure (so we can strongly type against it), then retrieve live data by calling .Load
type WikiSurreyLeighStructure = HtmlProvider<"data_structure.html">
let liveDataTable = WikiSurreyLeighStructure.Load("https://en.wikipedia.org/wiki/Leigh,_Surrey").Tables.``Demography and housing 2``

//Prepare data scraped from the web page (details on the housing types in Leigh, Surrey)
let propertyTypeData = [
    String.Format("Detached ({0})", liveDataTable.Rows.[0].Detached), liveDataTable.Rows.[0].Detached
    String.Format("Semi-Detached ({0})", liveDataTable.Rows.[0].``Semi-detached``) , liveDataTable.Rows.[0].``Semi-detached``
    String.Format("Terraced ({0})", liveDataTable.Rows.[0].Terraced), liveDataTable.Rows.[0].Terraced 
    String.Format("Apartments ({0})", liveDataTable.Rows.[0].``Flats and apartments``), liveDataTable.Rows.[0].``Flats and apartments`` ]
 
//Display this data in a styled pie chart     
Chart.Pie(propertyTypeData
).WithTitle(Text = "Property Types in Leigh (Surrey)", FontSize = 26.00, FontStyle = FontStyle.Bold
).WithStyling(BorderColor = Color.BlueViolet, BorderWidth = 2
).With3D()

//---------------PIE CHART EXAMPLE TWO---------------
 
//Provide a type that outlines the page 'structure', so we can strongly type against it
type PopulationHtmlStructure = HtmlProvider<"data_structure_two.html">
 
//Retrieve live page data (and the relevant population html table)
let populationLiveDataPage = PopulationHtmlStructure.Load("https://en.wikipedia.org/wiki/Demography_of_the_United_Kingdom")
let populationLiveDataTable = populationLiveDataPage.Tables.``Age structure 2``
 
//Extract some data for Males and Females
let allPopulationData =
    [
        String.Format("Male ({0})", populationLiveDataTable.Rows.[4].Population), populationLiveDataTable.Rows.[4].Population;
        String.Format("Female ({0})", populationLiveDataTable.Rows.[4].Population2), populationLiveDataTable.Rows.[4].Population2;
    ]

//Simpler syntax, just call Chart.Pie with no extra bells and whistles
allPopulationData
|> Chart.Pie
 
//Produce a 3D pie chart, with some custom styling, based on this data
Chart.Pie(allPopulationData
).WithTitle(Text = "Population by Gender (Millions) - UK", FontName = "Verdana", FontSize = 26.00, FontStyle = FontStyle.Bold
).WithStyling(BorderColor = Color.AliceBlue, BorderWidth = 2
).With3D()

//#endregion Pie Chart

//#region Point Chart

//Declare and bind another 'random'
let anotherRandomValue = new Random()

//Create a basic point chart using the simpler |> syntax (denoting we are calling the basic Chart.Point constructor with no frills)
[for i in 0..500 -> anotherRandomValue.NextDouble(), anotherRandomValue.NextDouble()]
|> Chart.Point

//What does it look like in 3D. Hmmmm, not great!
Chart.Point([for i in 0..500 -> anotherRandomValue.NextDouble(), anotherRandomValue.NextDouble()]).With3D()

//#endregion Point Chart

Fighting The Python

A random spin-off for today, but thankfully a much, much shorter post for anyone who bled from their eyeballs when reading my last post! The focus for today is Python; what you’ll read about here is my initial insights. Looking at the clock, this equates to about just under an hour of reading and learning; so don’t expect to see anything too advanced or perhaps even technically perfect (sound the ‘possibly wrong on the internet alarms now please, if you will’).

What is Python?

Everyone, I’m sure, just wants to say it’s a big-ass snake; and of course it is! Programming language wise however, Python is designed to be a very easy to read, terse, dynamically typed language which allows for rapid development. I’m familiar with it from a procedural/scripting sense but Python does support an object-orientated paradigm (something I haven’t looked into as of the time of writing).

So, some re-iteration here but bear with me; the key takeaway points are:

  • Dynamically typed.
  • Standard files use the .py extension.
  • Whitespace sensitive (uses indentation, like F#, to control flow).
  • Similar ethos to F#, easy to read and terse.
  • Allows for rapid development cycles.
  • Information that I’ve gathered so far touts this as a great starter programming language.

Setup

You’ve got a few options for getting started. There appears to be multiple online interpreters where you can go and code in Python without downloading any resources:

Python Online Interpreters (Google)

Codecademy also has a course on offer which you can review, which I used as a primer for writing this post (the first few sections at least). The python.org site also has, based on an initial nosey around, some solid looking documentation along with downloads for the latest versions of Python:

Codecademy Python Course
www.python.org (Downloads/Documentation)

As I’m a Windows/Visual Studio kind of guy (something I should probably step away from occasionally to properly fly the ‘Random Coding Journeys’ banner in future!) the examples you’ll see next are formed using the Python Visual Studio templates (for creating a Python Command Line Application).

On debugging the application for the first time you will be prompted to download an interpreter; CPython is the option I selected, but there were various options to peruse so if you try this yourself have a good root around. After one, simple, installation I was away and debugging.

Python VS Interpreter.

Python VS Interpreter.

Python Command Line.

Python Command Line.

So, without further ado, let’s get to some coding!

The Basics

As Python is dynamically typed, as stated before, to get up and running you simply declare a variable name, followed by the equals (‘=’) operator, then a value to start working with data as follows:

language = "Python"

Python then uses a type inference system (much akin to F# again) as you would expect.

Single-line comments are defined using #, with multi-line comments requiring content to be wrapped inside triple double quotes:

#A single-line comment
language = "Python"

"""
A multi-line comment
"""
intNumber = 10

A super-fast blast through the documentation on the python.org site and codecademy illustrates that the +, -, *, / and % operators all function as you would expect. The ** syntactic rule is used for exponential operations. The input/print functions can be used read in/output information to the console respectively. The def keyword is used to define functions (parameters can be supplied using parentheses). In a slight syntactic twist to what I’m used to, colons are used at the end of if, elif, else, try and except statements before any newlines/indentation:

#Classic Hello World - Just in case you really, really wanted to see it!
print ("Hello World")

print (5 + 5)       #Addition (10)
print (10 - 5)      #Subtraction (5)
print (5 * 5)       #Multiplication (25)
print (10 / 5)      #Division (2.0)
print (10 % 4)      #Modulo/Modulus (2)
print (10 ** 2)     #Exponential (100) 

#Get a number input from the user
intValue = input("Enter any number: ")

#No checking on ints here - Completely unsafe cast (gulp!)

#Notice the use of colons here. Stardard ==, <, >, etc operators are fine. Can also define an 'in' statement (if, elif and else supported)
if int(intValue) <= 8:
    print("intValue less than or equal to 9")
elif int(intValue) in (9, 10, 11):
    print("intValue in 9, 10, 11")
else:
    print("intValue is greater than or equal to 12")

#Retrieve another input from the user
intValueTwo = input("Enter another number: ")

#Illustrate some other decision making constructs. 'or' and 'and' are substituted (when compared to C#) for && and ||
if int(intValueTwo) == 0 or int(intValueTwo) == 1:
    print("intValueTwo is 0 or 1")
elif int(intValue) > 10 and int(intValueTwo) == 2:
    print("intValue is greater than 10 and intValueTwo is equal to 2")
else:
    print("Some other condition")

Sample Application

To finish this post off here’s an incredibly rudimentary code sample that’s designed to calculate the hypotenuse of a right-angled triangle (with the lengths of the two shorter sides of the triangle provided):

"""
A basic example of using python: Pythagoras' Theorem (and a multi-line comment!)
"""
#Import math helpers as required
from math import sqrt, floor

#Create a function up front to parse the input to an integer (that's all I'm allowing for now). Basically to demonstrate very simple error handling
def intTryParse(value):
    try:
        int(value.strip())
        return True
    except ValueError:
        print("Could not convert input value to an integer.")
    except:
        print("Unknown error occurred whilst processing the input.")
    return False

#Create a function to calculate the third side (assuming we have a right angled triangle!) of a triangle based on the two side lengths provided
def calculateTrianglesThirdSide(firstSideLen, secondSideLen):
    return floor(sqrt((firstSideLen ** 2) + (secondSideLen ** 2))) #Use floor to round, ok with the slight inaccuracy (I just wanted to use more helper functions)

#print to the console - We're here and we are alive!
print ("Pythagoras Example (calculate Hypotenuse)\r\n=========================\r\n")

#Get string based input from the user for the first two sides of the triangle
sideOne = input("How long is the first shortest side of the triangle: ")
SideTwo = input("How long is the second shortest side of the triangle: ")

#Only proceed if both values provided are integers
if intTryParse(sideOne) and intTryParse(SideTwo):
    #Both values provided for the first two sides parse correctly (strip space from the values)
    sideOneInt = int(sideOne.strip())
    sideTwoInt = int(SideTwo.strip())

    #Calculate the remaining side using the values provided (output to the console)
    print (calculateTrianglesThirdSide(sideOneInt, sideTwoInt))
else:
    #Invalid input - Cease processing
    print ("Processing halted due to invalid input.")

Thanks for reading, until the next time…

A Few Hours With….F#

What can I learn about F# in the time it takes to drink a coffee, eat some biscuits and listen to a few tracks on Spotify; let’s find out. This post was supposed to be entitled “Thirty Minutes With…F#” but I ended up getting far too engrossed and a couple of hours skipped by (followed by more coffee and biscuits)!

This is something that I’ve been meaning to cover and is a topic that has come up among friends and colleagues; there’s certainly an interest in this language so I’ll pop the hood and have a little look.

For starters, although it’s a few years old now, I found this discussion on the topic interesting:

F# with Richard Minerich & Phillip-Trelford (Hanselminutes.com)

As a basis for this little peek, I’ll be using http://www.tryfsharp.org, instead of any of the integrated Visual Studio features (which do exist, so I may do a follow up after this taster).

EXTRA NOTE: In the interim since starting this post, I actually attended the Future Decoded 2015 event where there was a fantastic F# breakout session by Don Syme; this has very much peaked my interest further.

What is F#?

Prior to writing this post I’d pegged F# as a scripting language geared to solving complex mathematical problems in a clean manner; hence its inherent link with the financial market and software created to function in this particular sector. However, based on the Hanselminutes.com podcast and the content presented on tryfsharp.org, it seems as if I may possibly be underselling it. We find that F# is now pushing itself as a fully-featured and rich alternative (or at least considering itself as a powerful language to commonly interoperate with, not just for mathematical problems) to existing object-orientated languages such as C# and Java.

So, the take away points:

  • Strongly-typed, functional-first programming language.
  • Open source.
  • Cross platform.
  • Expressive and concise (i.e. terse).
  • Whitespace Sensitive.

Setup

When using the tryfsharp.org site, the first hurdle that you’ll have to jump is compatibility issues with the Silverlight plugin used to drive the web editor. During my testing I had issues in Chrome and Edge, as outlined below:

Chrome Unsupported.

Chrome Unsupported.

I came up trumps in FireFox, IE 11 and Opera (for now):

Opera Supported!

Opera Supported!

I settled on using FireFox and didn’t come across any issues whilst going through the tutorials presented in the getting started section. Perhaps the browser compatibility is something that will get addressed or is something that I just need to read up on. Silverlight is still slowly coughing and spluttering its way to an eventual demise either way!

Getting Started in F# – Section by Section

I’m going to give a very basic and brief rundown of the content presented in the first few sections provided on the site. This isn’t an exhaustive list of all of the content presented or a full representation of the information available; this just represents my first ‘comb through’.

Bindings, Values and REPLs

To begin with, we are presented with the REPL (Read Evaluate Print Loop), which executes the code within the editor. The REPL provides an on-going output so you can build up programs incrementally (i.e. keep a track of basic mathematical output for instance). You can opt to execute code in its entirety, in blocks or line by line by highlighting statements and using the run command (or using Ctrl+Enter). One gotcha here, the equivalent command in Visual Studio called F# Interactive, which allows you to execute scripts line by line or in blocks, requires you to use Alt+Enter. I’ve seen resources that state this could cross over with some Re-Sharper keyboard shortcuts; this is one to look out for and adjust key bindings as required.

Binding names to values (declaring and setting variables in a traditional sense) is achieved using the let keyword:

//Declare and set a variable called bookCount to 10
let bookCount = 10

In a variation to C#, let bindings are immutable in F#, meaning that out of the gate the following with cause errors and behaviour you may not expect if you’re not on your guard:

//The following code results in "Book Count: 10" - bookCount does not allow mutation after the original assignment (binding)
let bookCount = 10 
bookCount = 11 
printfn "Book Count: %d" bookCount          //printfn is a utility function (in FSharp.Core.dll) that allows printing to the output window (various formats are allowed for variables that you want to inject into the resultant string)

//Duplicate definition of value 'valueOne' error thrown
let valueOne = "Value One"
let valueOne = "Value Two"

You’ll notice that I’ve thrown in a reference to the printfn function; a real staple for providing formatted output as and when needed. Further help can be found here:

Core.Printf Module

So what if you need to actually ‘mutate’ a value after its original assignment? Thankfully, this is possible via the mutable keyword, as illustrated in this simple example of a looping construct:

//Declare a particular variable using the mutable keyword so the value can change after assignment
let mutable countVar = 1
 
for item in itemArray do
    //Perform some kind of function (using the countVar value in this case)...
    countVar <- countVar + 1 //Increment countVar

As a side note, you can see that ‘<-' is used for assignment purposes (as opposed to the usual '=' operator).

Also, if executing statements singularly, it is possible to use a technique called shadowing to overwrite an initial binding as in this example:

//Executing this line...
let shadowed = "first value"

//Then this line, separately...
let shadowed = "second value"

//Prints "value = second value"
printfn "value = %s" shadowed

It’s important to note that the second statement here (let shadowed = “second value”) creates a new binding that shadows, or masks, the original.

F# is very much statically typed, as this code illustrates (types are inferred correctly in the output window on inspection):

let intTest = 10
let floatTest = 10.55
let stringTest = "Twenty Two"

A key plus of F# (as touted anyway) is that it goes to much greater lengths to perform type inference, to a larger degree than most statically/strongly typed languages. It’s looking to walk the very fine line between the enhanced readability of a dynamic language and the more robust nature of a statically typed language. My early impressions suggest that F# is doing a good job at finding a balance.

Functions

Functions in F#, in-line with traditional data values, are also created using the let keyword to bind a name to a function. You’ll notice that in a very simple function definition, such as in the next example, the specifying of types in relation to parameters isn’t strictly required. Based on how I’ve called the function F# infers the type of x and y to be integer:

let calculateRectPerimeter x y =
    ((x * 2) + (y * 2))

calculateRectPerimeter 4 6

As another example, this call to a function named multiply was defined using float values for both arguments; F# infers the types of these arguments correctly:

let multiply x y =
    x * y 

multiply 4.5, 6.2

A few gotchas crept into the fold here, namely surrounding mixing of types (integers and floats in my case) which, as opposed to C#, is not allowed in F# without explicit casting. Here’s a useful troubleshooting guide for anyone interested in doing some further reading:

F# Troubleshooting

So far you’ll have observed that the scaffolding required to define and use a simple function is very lightweight. No curly braces, brackets (until you start to enforce types as specified below) or comma-separation of arguments is required at this stage (which is quite nice I have to admit).

This leads nicely onto the topic of Type Annotations. In a nutshell, this simply means to define types in a function signature when the function operates on an input parameter in a type specific manner. This example is pulled directly from the learning resources provided online:

let toHackerTalk (phrase:string) =
    phrase.Replace('t', '7').Replace('o', '0')

toHackerTalk "terry ono"

F#, in wording stripped from the site, treats functions as First Class Citizens. This means, due to their nature of being bound to a name using the let keyword, you can create helpers functions within functions and use functions (as with C# methods) as arguments to other functions (termed Higher Order Functions):

//1) FUNCTIONS WITHIN FUNCTIONS

//Monthly pay is 4x weekly salary (addBonus doubles this value, if only!)
let calculateMonthlyPay x =    
    //Function defined within calculateMonthlyPay as an additional helper (called directly by this function)
    let addBonus x =
        x * 2

    addBonus(x * 4)

//Call calculateMonthlyPay ((250 * 4) * 2) = 2000    
let payResult = calculateMonthlyPay 250

//2) FUNCTIONS AS ARGUMENTS

//First, we define a simple test function that returns a fixed value
let magicNumber number =
    number 7

//Next, we create a function to test an input    
let testMagicNumber number =
    if number = 7 then
        "It's the magic number!"
    else
        "It's not the magic number..."

//Call testMagicNumber with the magicNumber function as an argument        
magicNumber testMagicNumber

This seemed very intuitive apart from, being completely honest, the nature in which you provide functions as arguments; these function arguments are defined before the function you want to call. A definite switch up from C# and something that made me stare at the screen for a couple of minutes :-?. Also, note the use of the ‘=’ operator for use in the comparison here, this doesn’t mean an assignment is occurring.

The last thing presented in this section is Lambda Functions, the syntax for which seems tight and easy to interpret for someone with a C# background:

//Lambdas (Anonymous Function) in action
let divide = (fun x y -> x / y)
divide 8 2

//testFunction returns 16
let testFunction test =
    test 16

//Using testFunction as an argument for an anonymous function (x will be 16). Divide (using our previous function) 32 by x, if the result is 2 or greater return true, else false
testFunction (fun x -> divide 32 x >= 2)

Chaining Functions and the Forward Pipe Operator

Hopefully anyone reading this hasn’t dozed off, head hitting the keyboard, etc so apologies in advance; this has turned into a bit of a ‘beast’! Thankfully, this particular section will be a little shorter.

For starters, lists in F# are handled in an incredibly succinct manner. You can create lists of defined values or a list based on a value range very easily as follows:

//A list of ages (note the semi-colon separation of values)
let ages = [24; 31; 32; 50]

//A list of numbers (0 through to 250 using the '..' syntax)
let aLotOfNumbers = [0..250]

//Just to prove it...
printfn "aLotOfNumbers has a length of: %d" (aLotOfNumbers.Length - 1)

Here, the lists are inferred to be of type int based on the contained values. I can see how this could be an incredibly useful way to do some load testing or as part of a larger unit testing strategy.

The List type provides functions for operating on lists, whether this be performing calculations, aggregation, filtering or projecting whole new lists. I worked with a few additional examples in my ‘culmination experiment’, but here I’ll focus on List.map and List.filter. Firstly, List.map is used to project a new data set based on the mapping function supplied. List.filter uses a predicate, which only provides results that return true for the given predicate. If using more than one ‘List’ function, as denoted by the training resources, you can use the Forward Pipe Operator to improve readability significantly:

//Bind a list using the let keyword (numbers 0 to 100)
let firstHundred = [0..100]

//Project a new list that contains numbers in the firstHundred list doubled
let doubledValues = List.map (fun x -> x * 2) firstHundred

//Filter values from 0 to 100 to even values only. Project a new list that contains these values doubled
firstHundred
List.map (fun x -> x * 2)
    (List.filter (fun x -> x % 2 = 0) firstHundred)
    
//Not using the let keyword this time, specify a starting list containing numbers 0 to 50 (Total = 1300) - Using Forward Pipe Operator
[0..50]
|> List.filter (fun x -> x % 2 = 0)     //Filter to only even numbers
|> List.map (fun x -> x * 2)            //Double the remaining numbers after filtering
|> List.sum                             //Sum the total values remaining (after filtering/doubling)

There’s a great stock data based example on the site listed at this point which I’ll leave for you to discover on your own 😉 (taking into account the size of this post so far!); needless to say it encapsulates the ideas covered here and served as a grounding for my forays in building the larger program below.

Data Structures

I haven’t yet delved into the F# object-orientated type system, but I did have just enough time to look over the more simplistic and lightweight options.

Record Types allow for the basic grouping together of data. The tutorial uses the example of a book, so I’ll use the source material directly to serve as an example:

//Book Record Type (outline for a 'Book' which defines fields and underlying types)
type Book = 
  { Name: string;
    AuthorName: string;
    Rating: int;
    ISBN: string }

//Type of Book inferred here based on the fields (properties) defined here matching the Book Record Type
let expertFSharp = 
  { Name = "Expert F#";
    AuthorName = "Don Syme, Adam Granicz, Antonio Cisternino";
    Rating = 5;
    ISBN = "1590598504" }

//Use the books Rating to provide output    
printfn "I give this book %d stars out of 5!" 
    expertFSharp.Rating

Record bindings are immutable also, so altering a books ‘Name’ for example will error. F# provides syntax for creating a new Record Type with an updated field value:

//Record Type bindings are immutable also; this throws an error
expertFSharp.AuthorName <- "Chris Marinos"    

//Create a new Book type, based on the existing book, with a new 'Name'
let partDeux = { expertFSharp with Name = "Expert F# 2.0" }

The type inference that occurs here can cause issues if another Record Type contains the same field names but with an opposing type. Thankfully, explicitly stating which type you want a bound value to relate to is as easy as specifying a prefix label on one of the field assignments (you only need to do one to cover the entire type):

type Book = 
  { Name: string;
    AuthorName: string;
    Rating: int;
    ISBN: string }

type VHS =
  { Name: string;
    AuthorName: string;
    Rating: string;                                                 // Videos use a different rating system.
    ISBN: string }

//Binding fixed here by using Book.Rating
let expertFSharp = 
  { Name = "Expert F#";
    AuthorName = "Don Syme, Adam Granicz, Antonio Cisternino";
    Book.Rating = 5;                                                //Using the explicit label 'Book' here means this in its entirety is now treated as a Book, neat trick            
    ISBN = "1590598504" }

In the scenario whereby a particular field may or may not contain a value (the classic nullable scenario), F# defines the option, Some and None keywords. I’d love to read up on this further; the approach, to me at least, seems to be to create a safety blanket that doesn’t allow for the pesky null reference exception. When calling traditional .Net code this will still be an issue of course; but within the realm of F# the idea of making the developer accountable for this state management (and not just letting something ‘be null’) really intrigues me – Note to self for further reading! In addition, you are able to use a Pattern Matching check using the match/with construct. Here’s a complete example to whet the whistle:

//All people have a Name and Age, but not all people have a Book Club Membership Number
type Person = 
    { Name: string;
      Age: int;
      BookClubMemNo: int option }   //option denotes that data may not exist

//Define Steve - He has no Book Club Membership (None keyword used represent this)   
let steve = 
    { Name = "Steve Smith";
      Age = 32;
      BookClubMemNo = None }
      
//Define Jane - She loves her books, therefore she has a Book Club Membership (Some 'value' used to represent this)
let jane = 
    { Name = "Jane Smith";
      Age = 29;
      BookClubMemNo = Some 125485422 } 
      
//Define a function to 'Pattern Match' - Does the BookClubMemNo of a person have a value?
let bookClubMemDetails person =
    match person.BookClubMemNo with
        | Some memNo -> printfn "%s has a Book Club Membership Number of %d" person.Name memNo
        | None -> printfn "%s has no Book Club Membership" person.Name

//Test our function
bookClubMemDetails steve
bookClubMemDetails jane
Pattern Matching In Action.

Pattern Matching In Action.

The last thing I’d like to discuss, and is the final item on the learning resources checklist for getting started, is Discriminated Unions. These look and feel, on the face of it, like something akin to a C# enum type. You can use the same Pattern Match construct (which is very much an equivalent, in a basic sense, to a ‘case’ statement) as above to operate on a Discriminated Union. As a final note, and you’ll see this in the code sample below, Discriminated Union members can be ‘bundled’ together to create more complex scenarios (i.e. defining a sponsor type that’s associated with large football clubs sponsor).

Melting Pot Example

So, as a culmination to what I’d managed to glean in the first hour and a bit, I came up with a little fictional, football data interrogation sample (because…urm, I’m geeking out!). Here’s the final code sample and full comments to boot:

//Test Scenario
//------------------------
//Calculate football team point totals (only for teams whereby they have 10 or more wins) and provide the name of the team who is winning the league

//Defines a teams strip colour options
type StripColour =
| Red
| Yellow
| Green
| Blue

//Defines some secondary information about teams sponsors and sponsor sizes
type LargeSponsorSubTypes =
| Finance
| Oil
| Military

type SponsorSizeType = 
| Large of LargeSponsorSubTypes     //Large sponsors have a defined sub-type as above
| Medium
| Small

//Defines the structure of a football team data item
type FootballTeam =
    { Name: string;
      Wins: int;
      Draws: int; 
      MainKitColour: StripColour;
      SponsorSize: SponsorSizeType option
      Sponsor: string option; }

//Defines a data set surrounding football teams win/draw total (data items type inferred based on 'property' names)
let footballTeamData = 
    [
        { Name = "Roaring Tigers FC"; Wins = 8; Draws = 10; MainKitColour = Red; SponsorSize = Some Small; Sponsor = Some "Tiger Juice" };
        { Name = "Squeaking Mice Town"; Wins = 13; Draws = 6; MainKitColour = Green; SponsorSize = None; Sponsor = None };
        { Name = "Elephant City FC"; Wins = 12; Draws = 3; MainKitColour = Yellow; SponsorSize = Some Medium; Sponsor = Some "Elephant House Movers" };
        { Name = "Lazy Leopard Wanderers"; Wins = 3; Draws = 6; MainKitColour = Blue; SponsorSize = None; Sponsor = None };
        { Name = "Jolly Pirates FC"; Wins = 16; Draws = 6; MainKitColour = Green; SponsorSize = Some Small; Sponsor = Some "Pirate Clothing"; };
        { Name = "Norwich City FC"; Wins = 9; Draws = 9; MainKitColour = Yellow; SponsorSize = Some (Large Finance); Sponsor = Some "Aviva"; };
    ]

//Helper function to calculate a teams points based on wins and draws
let calculatePoints wins draws =
    ((wins * 3) + draws)
 
//1) Who is leading the league as it stands (based on total points) - In my weird and wonderful world you must have at least 10 wins to be included in the calculation
printfn "\r\nCurrent League Leader\r\n==============================" 
   
footballTeamData 
|> List.filter(fun team -> team.Wins >= 10)                                                                                     //10 win minimum
|> List.maxBy(fun team -> calculatePoints team.Wins team.Draws)                                                                 //Get the max by the amount of points the team has got                    
|> (fun team -> printfn "%s is leading the league with %d points.\r\n" team.Name (calculatePoints team.Wins team.Draws))        //Print out the teams name and points total

//DO SOME OTHER PROCESSING FOR FUN
//2) Print out a league table (all teams included - Order by point totals)
printfn "Current Standings and Team Information\r\n=============================================" 

let orderedTeamData = 
    footballTeamData
    |> List.sortBy(fun team -> -calculatePoints team.Wins team.Draws)       //Seems to be a sortByDescending in F# 4.0, the negative hack fits purpose here for the time being
    
let mutable teamPlace = 1 
for team in orderedTeamData do
    printfn "%s is at position %d in the league with %d points and a %A kit colour." team.Name teamPlace (calculatePoints team.Wins team.Draws) team.MainKitColour
    teamPlace <- teamPlace + 1
    
//3) Process team sponsors and types and do some pattern matching to finish up
printfn "\r\nTeam Sponsor Information\r\n=============================================" 

//Define a helper function to process each teams sponsor information
let handleTeamSponsorInfo team =
    match team.SponsorSize with
    //Team has a sponsor size so keep interrogating data (we have a sponsor name)
    | Some sponsorSize -> match sponsorSize with
                            //Handle each sponsor size separately (large sponsors have a sub-type so demonstrate how these could be handled differently)
                            | Large largeSponsorSubType -> match largeSponsorSubType with
                                                            | Finance -> printfn "%s has a Large-sized Sponsor (name: '%A') with a Finance subtype. As this is Finance based do blah blah..." team.Name team.Sponsor
                                                            | Oil -> printfn "%s has a Large-sized Sponsor (name: '%A') with an Oil subtype. As this is Oil based do blah blah..." team.Name team.Sponsor
                                                            | Military -> printfn "%s has a Large-sized Sponsor (name: '%A') with a Military subtype. As this is Military based do blah blah..." team.Name team.Sponsor
                            | Medium -> printfn "%s has a Medium-sized Sponsor (name: '%A')." team.Name team.Sponsor
                            | Small -> printfn "%s has a Small-sized Sponsor (name: '%A')." team.Name team.Sponsor
    //No sponsor size (hence, no sponsor type as defined by the data I've rigged for this example)
    | None -> printfn "%s has no sponsor." team.Name
    
//Call the function to inspect team sponsor info (for each and every team in the original, un-ordered data set)
for team in footballTeamData do
    handleTeamSponsorInfo team
    
//TO IMPROVE 
//-> Include a team 'Points' property and calculate this up front (to reduce calls to calculatePoints)
//-> Alter formatting options to remove the 'Some' part of the output within the handleTeamSponsorInfo function

Type Providers

I had another half hour to spare, and I desperately wanted to (following the Future Decoded demonstrations) have a very quick play with F# Type Providers. This example doesn’t go into charting, which I’ll reserve as a cherry-on-top topic for another day, but covers an example of scraping a web page for data using the HtmlProvider. In the example below I’m pulling data on browser usage from the w3schools website (directly from a table on the browser_stats.asp page of the site).

The basic premise is that you provide a sample HTML snippet to define a ‘type’; this essentially gives you strongly typed members to run with in order to rip information out of a web page on-demand. You’ll notice that this approach is indeed sensitive to restructuring changes made at the website page level, which is to be expected, but it’s an interesting premise for interrogating online data sources in real-time.

Here’s the full code snippet, produced in Visual Studio this time around with a NuGet package installed for FSharp.Data:

//Bring the FSharp.Data namespace into scope
open FSharp.Data

//Define a type to house browser stats information (based on an example file)
type BrowserStats = HtmlProvider<"DataFormat.htm">

[<EntryPoint>]
let main argv = 

    //Retrieve the latest, 2015, browser statistics for w3schools (example file defines a 'outline' so we know how the data is structured - A schema of sorts)
    let browserStatInfo = BrowserStats.Load("http://www.w3schools.com/browsers/browsers_stats.asp").Tables.``Browser Statistics``

    //Write a title to the console
    System.Console.WriteLine("2015 Browser Statistics\r\n=============================\r\n")

    //Write, to the console, stats for each browser (row by row from the relevant html table)
    for row in browserStatInfo.Rows do
        System.Console.WriteLine("{0} -> Chrome: {1}, IE: {2}, FireFox {3}, Safari {4}, Opera {5}", 
            row.``2015``, row.Chrome, row.IE, row.Firefox, row.Safari, row.Opera)

    //Do not close until we have had time to inspect the data
    System.Console.ReadKey() |> ignore

    0 // return an integer exit code

Example output from the console application utilising the above code:

Browser Statistics Console Output.

Browser Statistics Console Output.

In summary, I’ve really enjoyed working with F# (in this initial exploratory sense). I can certainly see enough here to warrant a further deep dive and possibly purchasing a book here or there down the road. I hope you’ve enjoyed reading through. Now, where did I put my semi-colons again, I can’t find them at the end of any statements…

All the best!