Welcome to MSDN Blogs Sign in | Join | Help

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.

Published Friday, August 29, 2008 6:09 PM by andrewkennedy
Filed under: , , ,

Comments

Friday, August 29, 2008 4:54 PM by Jomo Fisher -- Sharp Things

# F# 1.9.6.0 Link Roundup

- Units of Measure in F#: Part One, Introducing Units [ reddit ] [ digg ] - Welcome to the F# CTP project

Friday, August 29, 2008 5:33 PM by MichaelGG

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

This is fantastic. I had come across your page last night and seen this. What a surprise to see this included in F# the next morning! Thank you for F#.

Friday, August 29, 2008 9:29 PM by Pon

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

Indeed, this is awesome.

However, what about things such as:

type Vector = struct

  val X:float

  val Y:float

  val Z:float

new(x,y,z) =

 X= x

 Y = y

 Z = z

Would I be able to do something like

Accelerate(Vector(1.0<m/s>, 1.0<m/s>, 1.0<m/s>), 3<m s^-2>, 2.0<s>)?

Friday, August 29, 2008 9:33 PM by Pon

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

And, if I am, what will the Vector structure appear to be to non-F# code?

Saturday, August 30, 2008 1:18 AM by Matthew Podwysocki

# F# Releases September 2008 CTP!

Don Syme just announced today the F# Community Technical Preview (CTP) Release September 2008 which is

Saturday, August 30, 2008 1:20 AM by Matthew Podwysocki's Blog

# F# Releases September 2008 CTP!

Don Syme just announced today the F# Community Technical Preview (CTP) Release September 2008 which is

Saturday, August 30, 2008 1:55 AM by Community Blogs

# F# Releases September 2008 CTP!

Don Syme just announced today the F# Community Technical Preview (CTP) Release September 2008 which is

Saturday, August 30, 2008 5:18 PM by andrewkennedy

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

Pon: yes, you can *parameterize* other types (such as Vector) on units-of-measure. Here's an example, in which the value v has type Vector<m/s>. More on this in another article, coming soon!

- Andrew.

[<Measure>] type m

[<Measure>] type s

type Vector< [<Measure>] 'a> = struct

 val X:float<'a>

 val Y:float<'a>

 val Z:float<'a>

 new(x,y,z) = {X=x;Y=y;Z=z}

end

let v = Vector(2.0<m/s>,3.0<m/s>,4.0<m/s>)

Saturday, August 30, 2008 9:42 PM by MikeGale

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

Thanks for this.

It's a real pleasure to see a "real sytem" implemented.  Proper engineering and scientific calculations (and graphs...) have for a long time been ignored in computer science, often by ignorance.

Now we don't have to roll our own for a lot of what is needed.

Sunday, August 31, 2008 1:26 AM by Chris Smith's completely unique view

# FSharpp to FSProj Converter

Wow, what a busy week!&#160; The F# CTP is out the door, and it's already making reverberations around

Sunday, August 31, 2008 5:39 AM by Pierrick's Blog

# F# nouvelle CTP (1.9.6)

Que dire de cette CTP , si ce n' est qu' elle est mieux intégrée dans Visual Studio. intellisense de

Sunday, August 31, 2008 7:37 AM by Hiroshi Okagawa

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

Cool!

As my major at university was Physics, unit checking and inferring are more natural than type checking and inferring.

Let me ask a question.

1) "dimensionless" float

In physics, some quantities doesn't have dimensions and the fact that it is dimensionless is important.

For example, "Reynolds number" in flued mechanics.

(http://en.wikipedia.org/wiki/Dimensionless_quantity)

My question is, are there any way to require a float to be dimensionless in F#?

2) Assert by units

I don't know whether possible or not, but I think it would be very interesting if I could embed assertion by units and can be checked statically.

Something like following:

     :

 let m = accel / time / time

 assert(m:float<kg>)

 let x = m / mass

 assert(x:float<"dimensionless">)

     :

Anyway, this is a great job and I hope you to keep moving forward to improve F#!

Sunday, August 31, 2008 12:15 PM by Thoughts and Code

# F# September CTP

Ευχάριστα νέα για τους φίλους της F#, καθώς έχουμε στα χερια μας το πρώτο release της productized πλέον

Sunday, August 31, 2008 1:35 PM by kfarmer

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

@Microsoft:  PLEASE convince Anders, Brad, etc to figure out a way to bake this into the CLR type system.  There are other languages than F# (eg, Python, C#) that science geeks use.  :)

@Hiroshi:

and what should assert(m:float<kg>) mean?

.. assert that m has the same axes as kilograms?  (eg, float<lb>, float<g>, float<solarMass> .. all would succeed)

.. assert that m is a float of kilograms? (eg, float<lb>, etc would fail)

These are very different questions, but the way the assert is written it's impossible to tell what is meant.

Re "dimensionless" quantities:

These differ from scalars how?  Should counts (eg, Avogradro's number) be handled differently?

This is actually a peeve of mine in the way the mathematical powers-the-be have treated angular measure.  

Sunday, August 31, 2008 1:57 PM by int19h

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

This is seriously great; however, it begs the question: can those unit types be used for numeric types other than float? Can I use, say, decimal? Or even int? What if I want to roll out my own BigInteger/BigDecimal - will I be able to hook it into the type system seamlessly to the end user?

Sunday, August 31, 2008 2:50 PM by int19h

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

Also, it strikes me odd that I can't write something like:

 [<Measure>] type g

 [<Measure>] type kg = 1000 * g

let x = 1.0<kg>

Of course I could treat kg as a val rather than type:

 let kg = 1000<g>

but then I can't use it in literal type suffixes.

Monday, September 01, 2008 6:05 AM by andrewkennedy

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

I'll have more to say in the next article, but just to answer some of these questions in brief:

* The built-in types float, float32 and decimal support units-of-measure, and units can be used on constants of these types. For example:

> 2.0f<kg>;;

val it : float32<kg> = 2.0f

> 200.0M<USD>;;

val it : decimal<USD> = 200.0M

>

* You can define your own types (e.g. vector, complex, etc.) parameterized on units-of-measure, with operations such as arithmetic. See the vector example earlier - more detail coming in a future article.

* Indeed you can define "related" units as values e.g. let g = 0.001<kg>. Alternatively, you can define separate types, and then define conversion factors with appropriate units. More in the next article in the series.

* The syntax for "no units at all", a.k.a. dimensionless, is "1". For example, float<1>, vector<1>. For the three built-in types, the non-parameterized variants are actually just aliases:

 type float = float<1>

 type float32 = float32<1>

 type decimal = decimal<1>

You can see this if you divide something with units by something else of the same type:

> let x = 2.0<kg>;;

val x : float<kg>

> x/x;;

val it : float = 1.0

>

Monday, September 01, 2008 3:41 PM by DotNetKicks.com

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

You've been kicked (a good thing) - Trackback from DotNetKicks.com

Sunday, September 07, 2008 3:38 PM by Andre

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

"An acceleration" or "a distance" is ambiguous, proper names would be linear acceleration and linear distance as a distance could also be a rotational distance.

Thursday, September 25, 2008 5:46 AM by Readed By Wrocław NUG members

# The Weekly Source Code 34 - The Rise of F#

First, let me remind you that in my new ongoing quest to read source code to be a better developer ,

Saturday, October 11, 2008 11:54 AM by Angel "Java" Lopez

# Recursos de F# y Programación Funcional

F# es un lenguaje funcional, creado por Microsoft. Implementado bajo el soporte de .NET CLR, es un lenguaje

Saturday, November 29, 2008 7:23 AM by Anders Cui

# F#中有趣的计量单位

NASA气象卫星意外坠落说明,计量单位绝非小事。为编程语言添加对计量单位的支持可以很大程度上避免这样的错误,编程任务也变得更有趣。F#提供了对计量单位的静态检查,并且封装了国际单位制的各个单位和物理常量,另外我们也可以定义自己的单位;在单位之间进行换算也很简单;此外F#还支持计量单位的泛型。作为对NASA气象卫星的纪念,本文最后给出了一个模拟太阳系的例子 :)

Wednesday, December 03, 2008 11:57 AM by qwertie

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

I'm puzzled. Why not allow unit checking on integers, or, for that matter, any type whatsoever? I wrote a units-of-measure extension to boo as a 5th-year undergrad project; this compiler step assumed that absolutely everything in a program had an associated unit. This fact had no effect on type checking until the user started annotating variables or constants with types, and then the unit inference engine worked its magic looking for inconsistencies.

In my engine, I just assumed certain rules about operators, like

'a + 'a -> 'a

'a - 'a -> 'a

'a * 'b -> 'a*'b

'a << _ -> 'a

(where _ means 'dimensionless')

Therefore any type that had these operators defined automatically got a reasonable default unit checking behavior.

There exist certain algorithms in which a variable has to take on different units at different points in time, so I also had a special annotation that (IIRC) disabled unit checking with respect to a specific variable.

Monday, March 30, 2009 11:10 AM by thefellow3j

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

Units!? YES! This is (the start of) EXACTLY what I need for my job *right now*! F# *just* peaked my interest.

I can't tell you how much I'll appreciate this feature.

Anonymous comments are disabled
 
Page view tracker