Welcome to MSDN Blogs Sign in | Join | Help

Units of Measure in F#: Part Four, Parameterized Types

It's been a while since I wrote anything on this blog. Now is a good moment to continue, with last week's Beta 1 release of Visual Studio 2010, including F#, and a refresh to the F# Community Tech Preview add-on for VS 2008. If you haven't yet installed either of these, I recommend that you do. There have been many bug fixes and improvements to F# since last year.

Since the initial CTP release of F# I've been busy fixing some bugs that have been uncovered, and giving talks on the units feature. I presented at the ML workshop that was co-located with ICFP'08, the International Conference on Functional Programming. (For the theoretically minded, I also gave a talk at the Workshop on Mechanizing Metatheory, or WMM for short.) A couple of weeks ago I presented a lecture course on units-of-measure to PhD and masters students, at the Central European summer school on Functional Programming, CEFP'09. The lecture notes from that course will be peer-reviewed and published by Springer later this year.

Now back to the blog tutorial. In the first three parts of this series, we saw how to define units-of-measure, how to use units with the built-in floating-point type float, and how to write code that's generic in units-of-measure.

There are two other built-in types with this feature: float32 (the type of single-precision floating point) and decimal. Here's how constants of these types are introduced:

image

But what if I want to create my own types with units, for example, complex numbers, 3-vectors, or matrices? That's easy: just parameterize the type, just as you might parameterize a type such as list or Dictionary, but mark the parameter with the [<Measure>] attribute:

image

As you can see, units beget units: in the Sphere type, we've used the Vector3 type, which in turn used the built-in float type. All are parameterized on units-of-measure.

Now we can create a point and acceleration, both vectors, but with different units:

image

That was easy enough. Now let's define some operations on vectors:

image

Notice how F# inferred a generic type for dot product. Of course, we'd really like to extend operators such + and - with overloads for our new type. To do this, we can define static members on the type:

image

There are a couple of things to notice here. First, we've given the units of the arguments explicitly. If we don't do this, then F# will infer extra unit parameters rather than using the unit parameter 'u from Vector3 itself. Second, we have implemented various kinds of multiplication: multiplying a vector on the left and on the right by a scalar (i.e. a float), multiplying a vector by a vector to get the vector product, also known as the cross product, and finally, the dot product, which we've called '.*'. In order to define multiple overloads for *, we've used the OverloadID attribute to distinguish them. Now let's look at the signature that F# gives to this type, by hovering the cursor over the declaration:

image

We can now implement a "vector" version of Newton's second law (F = ma), multiplying a scalar mass by an acceleration vector to get a force vector:

image

The use of records in the Vector3 type is a traditional functional programming approach. A more .NET-oriented style of definition is to define a class with implicit constructor, instead of a record type. Here's a type for complex numbers defined this way, including instance members to obtain the polar representation of complex numbers as magnitude and phase, and to print complex numbers in the form a + ib:

image

One "gotcha" here is the need for explicit type signatures on the re and im properties. Without these hints, F# infers weaker types for arithmetic (try it!). Fortunately, this issue will be resolved in the final release of F#.

We can now do some electrics!

image

Executing this code in F# Interactive produces:

image

The amplitude of a voltage value has type float<V>, whilst the phase has type float, being measured in radians.

Summing up. We've seen how to parameterize user-defined types on units-of-measure, how to define members that make use of the unit parameters, and how to overload operators to define non-standard arithmetic.

Next time we'll have a look at the internals of type checking and type inference for units-of-measure. You don't need to know this to use the units feature, but you might be curious anyhow. For instance, however does F# figure out the type of the following?

image

Units of Measure in F#: Part Three, Generic Units

In the first two articles in this series, we saw how to declare base and derived units, introduce constants with units, define our own conversion functions, and have F# check the units for us.

But what if we're writing code that doesn't care what units it is working in? That's the subject of today's article.

Let's start simple. What is the type of fun x -> x*x? Well, multiplication is overloaded, so F# defaults to integers:

image

But if we annotate the argument, we can define squaring for all kinds of floats (hovering over the last of these to show its type):

image

This looks painful! What if we don't tell F# what the units are, using the underscore notation to say "find me its units"?

image

F# has inferred a generic unit type for squaring. The notation 'u looks like a type parameter, but is in fact a unit-of-measure parameter that can be instantiated at any units. Let's use it on masses, lengths and speeds:

image

F# can infer generic unit-of-measure types with type annotations required only to resolve overloading. Here are some simple examples, tested out in F# Interactive:

image

Here's one that requires a bit of head-scratching to understand:

image 

Returning to reality, suppose we want to sum the elements of a list. In true functional style, we use one of the fold operators.

image

Oops - we don't seem to have a nice generic type! The reason is simple: unless units are specified, constants, including zero, are assumed to have no units, i.e. to be dimensionless. So instead, let's give 0.0 some units, but not tell F# what they are, by writing 0.0<_>:

image 

That's better!

Now we can go wild and write all sorts of statistical stuff.

image

And here are the beautiful types that are inferred for these functions:

image

Summing up: we've seen how to write code that is generic (a.k.a. as polymorphic) in units-of-measure.

Next time, we'll write types that are generic in units-of-measure. This makes the feature extensible: if floats with units aren't what you want, just define your own types!

Units of Measure in F#: Part Two, Unit Conversions

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?

Posted by andrewkennedy | 20 Comments
Filed under: , , ,

Units of Measure in F#: Part One, Introducing Units

Do you remember NASA's Mars Climate Orbiter? It was lost in September 1999 because of a confusion between metric and so-called "English" units of measurement. The report into the disaster made many recommendations. In all likelihood, the accident could have been prevented if the NASA engineers had been able to annotate their program code with units, and then employed static analysis tools or language-level type-checking to detect and fix any unit errors.

Of course, the languages that NASA used had no language or tool support for units. Many people have suggested ways of extending programming languages with support for static checking of units-of-measure. It's even possible to abuse the rich type systems of existing languages such as C++ and Haskell to achieve it, but at some cost in usability. More recently, Sun's Fortress programming language has included type system support for dimensions and units. It also happens to have been the subject of my PhD thesis from a few years ago. So it's particularly exciting for me that a feature which I studied in theory in 1995 will now get used in practice in F#.

As recently announced in the September 2008 F# CTP (Community Technical Preview), the F# programming language now has full support for static checking and inference of units-of-measure. In this series of articles I'll gently introduce the feature. (If you're not familiar with F#, look here.) We've already been testing out the units-of-measure feature inside Microsoft and I'm amazed at the diversity of applications that are turning up. Of course, there are the obvious applications to scientific computing, and games (which are all about physics, after all), but we're seeing applications in machine learning, finance, search (think click rates, etc) and others.

We'll start more traditionally, with units for mass, length and time. As it's the 21st century I'll use the modern incarnation of the metric system, the International System of Units, abbreviated SI from the French "Le Système International d'Unités".

image 

Here, the Measure attribute tells F# that kg, s and m aren't really types in the usual sense of the word, but are used to build units-of-measure. (You'll see in Part Two of this series of articles that they can have static members just like ordinary types in F#, but other than that they are quite different).

Now let's introduce some constants with their units, which we can do simply by tacking the units onto a floating-point number, in between angle brackets:

image

Notice how conventional notation for units is used, with / for dividing, and ^ for powers. Juxtaposition just means "multiply", and negative powers can be used in place of division, so you might prefer to express the units of acceleration slightly differently:

image

Or I might invite the wrath of my old physics teacher by writing it this way:

image

Now we can do some physics! If I jump out of my window, at what speed will I hit the ground?

image

You could try this in F# Interactive and see the result, or print it out. (It's about 8.3 metres per second. Ouch!) But more interestingly, hover the cursor over the variable and look at its type:

image

Magic! Units-of-measure are not just handy comments-on-constants: they are there in the types of values, and, what's more, the F# compiler knows the rules of units. To be more precise: the built-in type float takes an optional unit-of-measure parameter, written in angle brackets, in a similar way that types such as IEnumerable take a type parameter, as in IEnumerable<int>. When values of floating-point type are multiplied, the units are multiplied too; when they are divided, the units are divided too, and when taking square roots, the same is done to the units. So by the rule for multiplication, the expression inside sqrt above must have units m^2/s^2, and therefore the units of speedOfImpact must be m/s.

What if I make a mistake?

image

I've tried to add a height to an acceleration, so F# tells me exactly what I've done wrong. The units don't match up, and it tells me so!

Now let's do a little more physics. What force does the ground exert on me to maintain my stationary position?

image

We've just applied Newton's Second Law of motion. Being such a Great Man, Sir Isaac had a unit named after him: the newton, the SI unit of force. So instead of the cumbersome kg m/s^2 we can introduce a derived unit and just write N, the standard symbol for newtons.

image

Derived units are just like type aliases: as far as F# is concerned, N and kg m/s^2 mean exactly the same thing. 

Summing up. We've seen how to introduce base units, how to introduce derived units, and how to introduce constants with units. Everything else has followed automatically: F# checks that units are used consistently, it rejects code with unit errors, and it infers units for code that's unit-correct.

Next time we'll have a look at multiple unit systems, converting between units, and interfacing with non-unit-aware code.

Posted by andrewkennedy | 25 Comments
Filed under: , , ,
 
Page view tracker