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!

One thought on “A Few Hours With….F#

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