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!