In today's article I'll show you how to use different systems of units, convert between units, and interface with non-unit-aware code.

PowerPack goodies

First, though, let's have a look at some handy definitions provided in the F# PowerPack. To access this DLL, you'll need to reference if from your project. If you're working in Visual Studio, right-click on References in the Solution Explorer window.

image

Now select FSharp.PowerPack and click OK.

image

If you're working in FSharp Interactive, type

image

Now you'll have at your disposal the complete set of SI base and derived units, defined Microsoft.FSharp.Math.SI.

image

Also available are various physical constants, defined in Microsoft.FSharp.Math.PhysicalConstants.

image 

Multiple unit systems

So for physicists, at least, there is no excuse to go non-metric. But what if you insist? No problem! Here is the example from Part One, using feet instead of metres as the unit of length.

image 

What if you need to convert between feet and metres? First, define a conversion factor.

image

What are the units of feetPerMetre? Answer: feet per metre (doh!), or ft/m for short. Now we can convert distances...

image

...and speeds...

image

...and we can convert back the other way by multiplying instead of dividing:

image

As far as F# is concerned, ft and m have nothing to do with each other. It's up to you, the programmer, to define appropriate conversion factors. But the presence of units on the conversion factors makes mistakes much less likely. For example, what happens if I divide instead of multiply above? The type of the result suggests that something is awry, and will probably lead to a compile-time error later in the code:

image

It's probably a good idea to package up conversion factors with the unit-of-measure to which they relate. A convenient way to do this is to add a static member to the unit-of-measure "type":

image

Now we can just write ft.perMetre.

Interfacing non-unit-aware code

In Part One, we saw how to use syntax such as 2.0<s> to introduce units-of-measure into the types of floating-point values. But what if a quantity is stored in a file, or entered by the user through a GUI, or in a web form? In that case it'll probably start out life as a string, to be parsed and converted into a float. How can we convert a vanilla float into, say, a float<s>? Easy: just multiply by 1.0<s>! Here's an example:

image

If we want to convert back to a vanilla float, say, to pass to a non-unit-aware .NET method, we just divide by 1.0<s>:

image

Dimensionless quantities

But hang on a minute - what's going on with that last example? The variable timeInSeconds has type float<s>, and we divided it by 1.0<s> which has type float<s>. So the units cancel out, producing units which we write simply as the digit 1. Hence the type of timeInSeconds / 1.0<s> is float<1>. Such a quantity is called dimensionless. Conveniently, F# defines the ordinary float type to be an alias for float<1>,using the definition

type float = float<1>

which makes use of overloading on the arity (= number of parameters) of the type. (Overloading is used to similar good effect with the non-generic .NET type System.Collections.IEnumerable and its generic variant System.Collections.Generic.IEnumerable). 

Summing up, we've learnt about unit conversions of various kinds, between different unit systems, and between ordinary floats and floats-with-units.

Next time we'll look at generic unit types, or: what is a good type for fun x -> x*x?