Dis­claimer: I do not claim credit for the code exam­ples and much of the con­tents here, these are mostly extracts from the book by Chris Smith, Pro­gram­ming F#: A com­pre­hen­sive guide for writ­ing sim­ple code to solve com­plex prob­lems. In fact, if you’re think­ing of learn­ing F# and like what you read here, you should buy the book your­self, it’s easy to read and the author has gone go great lengths to keep things sim­ple and included a lot of code exam­ples for you to try out yourself.

Tuple

A tuple (pro­nounced “two-pull”) is an ordered col­lec­tion of data, and an easy way to group com­mon pieces of data together.

A tuple type is described by a list of the tuple’s ele­ments’ types, sep­a­rated by asterisks:

clip_image001

You can even have tuples that con­tain other tuples:

clip_image002

There’s a num­ber of ways to extract val­ues from a tuple, there’s fst (first) and snd (sec­ond) func­tions if you have a two-elements tuple:

clip_image003

And then there’s the let binding:

clip_image004

But remem­ber, you’ll get a com­pile error if you try to extract too many or too few val­ues from a tuple.

It is pos­si­ble to pass tuples as para­me­ters to functions:

clip_image005

Lists

Whereas tuples group val­ues into a sin­gle entity, lists allow you to link data together to form a chain. Doing so allows you to process list ele­ments in bulk using aggre­gate operators.

You can declare a list like this:

clip_image006

Notice in the snip­pet above the empty list had type ‘a list because it could be of any type, there­fore it’s generic.

Unlike other lan­guages, F# lists are quite restric­tive in how you access and manip­u­late them — there are only two oper­a­tions you can per­form with a list:

  1. The first is cons, rep­re­sented by the :: or cons oper­a­tor. This joins an ele­ment to the front or head of a list:

clip_image007

  1. The sec­ond is append, uses the @ oper­a­tor. Append joins two lists together:

clip_image008

List ranges

Declar­ing list ele­ments as a semicolon-delimited list quickly becomes tedious, espe­cially for large lists. To declare a list of ordered numeric val­ues, use the list range syntax:

clip_image009

If an optional step value is pro­vided, then the result is a list of val­ues in the range between two num­bers sep­a­rated by the step­ping value:

clip_image010

List com­pre­hen­sions

List com­pre­hen­sions is a rich syn­tax that allows you to gen­er­ate lists inline with F# code. The body of the list com­pre­hen­sion will be exe­cuted until it ter­mi­nates, and the list will be made up of ele­ments returned via the yield keyword:

clip_image011

Almost any F# code can exist inside of list com­pre­hen­sions, includ­ing things like func­tion dec­la­ra­tions and for loops:

clip_image012

When using loops within list com­pre­hen­sions, you can sim­ply the code by using -> instead of do yield:

clip_image013

Here’s a more com­plex exam­ple show­ing how you can use list com­pre­hen­sion to eas­ily find prime numbers:

clip_image014

List mod­ule functions

The F# library’s List mod­ule con­tains many meth­ods to help you process lists:

image

The fol­low­ing exam­ple demon­strates the List.partition func­tion, par­ti­tion­ing a list of num­bers from 1 to 15 into two new lists: one com­prised of mul­ti­ples of five and the other list made up of every­thing else:

clip_image015

The trick is that List.partition returns a tuple.

Aggre­gate Operators

Although lists offer a way to chain together pieces of data, there really isn’t any­thing spe­cial about them. The true power of lists lies in aggre­gate oper­a­tors, which are a set of power func­tions that are use­ful for any col­lec­tion of values..

List.map

List.map is a pro­jec­tion oper­a­tion that cre­ates a new list based on a pro­vided func­tion. Each ele­ment in the new list is the result of eval­u­at­ing the func­tion, it has type (‘a -> ‘b) -> ‘a list -> ‘b list

The fol­low­ing exam­ple shows the result of map­ping a square func­tion to a list of integers:

clip_image016

List.map is one of the most use­ful func­tions in the F# lan­guage, it pro­vides an ele­gant way for you to trans­form data.

List.fold

Folds rep­re­sent the most pow­er­ful type of aggre­gate oper­a­tor and not sur­pris­ingly the most com­pli­cated. When you have a list of val­ues and you want to dis­til it down to a sin­gle piece of data, you use a fold.

There are two main types of folds you can use on lists, first is List.reduce which has type (‘a -> ‘a -> ‘a) -> ‘a list -> ‘a

List.reduce iter­ates through each ele­ment of a list, build­ing up an accu­mu­la­tor value, which is the sum­mary of the pro­cess­ing done on the list so far. Once every list item has been processed, the final accu­mu­la­tor value is returned, the accumulator’s ini­tial value in List.reduce is the first ele­ment of the list.

This exam­ple demon­strates how to use List.reduce to comma-separate a list of strings:

clip_image001[7]

Whilst use­ful, reduce fold forces the type of the accu­mu­la­tor to have the same type as the list. If you want to use a cus­tom accu­mu­la­tor type (e.g. reduc­ing a list of items in a shop­ping cart to a cash value), you can use List.fold.

The fold func­tion takes three parameters:

  1. A func­tion that when pro­vided an accu­mu­la­tor and list ele­ment returns a new accumulator.
  2. An ini­tial accu­mu­la­tor value.
  3. The list to fold over.

The return value of the func­tion is the final state of the accu­mu­la­tor. The type of the fold func­tion is:

(‘acc -> ‘b -> ‘acc) -> ‘acc -> ‘b list -> ‘acc

Here’s an exam­ple of how you can use it to count the num­ber of vow­els in a string:

clip_image002[7]

Fold­ing right-to-left

List.reduce and List.fold process the list in a left-to-right order. There are alter­na­tive func­tions List.reduceBack and List.foldBack for pro­cess­ing lists in right-to-left order.

Depends on what you are try­ing to do, pro­cess­ing a list in reverse order can have a sub­stan­tial impact on per­for­mance.

List.iter

The final aggre­gate oper­a­tor, List.iter, iter­ates through each ele­ment of the list and calls a func­tion that you pass as a para­me­ter, it has type (‘a -> unit) -> ‘a list -> unit

Because List.iter returns unit, it is pre­dom­i­nately used for eval­u­at­ing the side effect of the given method, mean­ing that exe­cut­ing the func­tion has some side effect other than its return value (e.g. printfn has the side effect of print­ing to the con­sole in addi­tion to return­ing unit):

clip_image001[9]

Option

If you want to rep­re­sent a value that may or may not exist, the best way to do so is to use the option type. The option type has only two pos­si­ble val­ues: Some(‘a’) and None.

A typ­i­cal sit­u­a­tion you’ll use an option type is when you want to parse a string as an int and if the string is prop­erly for­mat­ted you’ll get an int, but if the string is not prop­erly for­mat­ted you’ll get None:

clip_image002[9]

A com­mon idiom in C# is to use null to mean the absence of a value. How­ever, null is also used to indi­cate an unini­tial­ized value, this dual­ity can lead to con­fu­sion and bugs. If you use the option type, there is no ques­tion what the value rep­re­sents, sim­i­lar to how System.Nullable works in C#.

To retrieve the value of an option, you can use Option.get.

clip_image003[7]

One thing to watch out though, is that if you call Option.get on None, an excep­tion will be thrown. To get around this, you can use Option.isSome or Option.isNone to check before the value of the option type before attempt­ing to access it, sim­i­lar to System.Nullable.HasValue in C#.

Printfn

printfn comes in three main flavours: printf, printfn, and sprintf.

printf takes the input and writes it to the screen, whereas printfn writes it to the screen and adds a line continuation.

pin­rtf has for­mat­ting and check­ing built-in (e.g. printfn “%s is %d%c high” moun­tain height units), it’s also strong typed and uses F#‘s type infer­ence sys­tem so the com­piler will give you an error if the data doesn’t match the given for­mat specifier.

Here’s a table of printf for­mat specifiers:

image

sprintf is used when you want the result of the print­ing as a string:

clip_image001[11]

Anatomy of an F# Program

Most other lan­guages, like C#, require an explicit pro­gram entry point, often called a main method. In F#, for single-file appli­ca­tions, the con­tents of the code file are exe­cute from top to bot­tom in order with­out the need for declar­ing a spe­cific main method.

For multi-file projects, how­ever, code needs to be divided into orga­ni­za­tion units called mod­ules or name­spaces.

Mod­ules

By default, F# puts all your code into an anony­mous mod­ule with the same name as the code file with the first let­ter cap­i­tal­ized. So if you have a value named value1, and your code is in file1.fs, you can refer to it by using the fully qual­i­fied path: File1.value1.

You can explic­itly name your code’s mod­ule by using the mod­ule key­word at the top of a code file:

clip_image001[13]

Files can con­tain nested mod­ules as well. To declare a nested mod­ule, use the mod­ule key­word fol­lowed by the name of your mod­ule and an equals sign =. Nested mod­ules must be indented to be dis­am­biguated from the “top-level” module:

clip_image002[11]

Name­spaces

The alter­na­tive to mod­ules is name­spaces. Name­spaces are a unit of orga­niz­ing code just like mod­ules with the only dif­fer­ence being that name­spaces can­not obtain value, only type dec­la­ra­tions.

Also, name­spaces can­not be nested in the same way that mod­ules can, instead, you can add mul­ti­ple name­spaces to the same file:

clip_image001[15]

It may seem strange to have both name­spaces and mod­ules in F#. Mod­ules are opti­mized for rapid pro­to­typ­ing and quickly explor­ing a solu­tion, as you have seen so far. Name­spaces, on the other hand, are geared toward larger-scale projects with an object-oriented solution.

Pro­gram Startup

For sin­gle file projects, the code will be exe­cuted from top to bot­tom, how­ever, when a you add a new file to the project, the newly added file will be run when the pro­gram starts up.

For more for­mal program-startup seman­tics, you can use the [<Entry­Point>] attribute to define a main method. To qual­ify, your method must:

  • Be the last func­tion defined in the last com­piled file in your project.
  • Take a sin­gle para­me­ter of type string array, which are the argu­ments to your program.
  • Return an inte­ger, which is your program’s exit code.
Share

One Response to “Learning F# – Part 4”

  1. Percy Leona says:

    This is the first blog I read on my new Droid Tablet. I’ll be back.. I’m cur­rently work­ing on Fish­bone Dia­gram project.

Leave a Reply