F# is clearly gearing itself for science and math. Well, most functional languages do since they frequently make it easy to express mathematical formulas naturally. One thing it does well is allow for measurements to be expressed using units. For example, let’s say that we need to compute the velocity of an object falling towards Earth. Things fall towards Earth at 9.8 m/s^2. To compute the speed of an object falling towards Earth after falling a fixed distance, we would find that we can simply multiple distance * velocity and wind up with m^2/s^2. To find speed, we take the square root of the product.
A common cause of bugs when performing this kind of calculation results from losing track of the units. How do we make sure that we at least know what the units are? For this kind of problem, F# introduces the Measure attribute. Measure allows a given, empty type to represent some type of unit. To represent meter and second, we would write:
[<Measure>] type m
[<Measure>] type s
Using these measures, we can then express Earth’s gravity as a value in meters/second^2
let gravityOnEarth = 9.81<m/s^2>
We can then express speedOfImpact against these values:
let speedOfImpact height = sqrt(gravityOnEarth * height)
Then, we can do something like find the speed after falling 100.0 meters. Pulling everything together, we have this:
1 #light
2
3 [<Measure>] type m
4 [<Measure>] type s
5
6 let gravityOnEarth = 9.81<m/s^2>
7 let speedOfImpact height = sqrt(gravityOnEarth * height)
8
9 printfn “%f” (float (speedOfImpact 100.0<m>))
This prints out
31.320920
Oh, if you forget to cast the result to a float, the compiler will tell you something like this:
The unit of measure ‘m/s’ does not match the unit of measure ‘1’
m/s– that’s a speed measurement! Note: the units of measure must appear immediately after the value represented. Any white space will give you this error on the next line:
incomplete construct at or before this point in expression
Now, before you write off F# as something that you could never use in a line of business application, consider the use of Measure for sales forecasting and other forms of capacity management. Items leave warehouses with a ‘velocity’ of widgets/unit of time. Here is a trivial example:
1 #light
2
3 [<Measure>] type widget
4
5 [<Measure>] type hour
6 let salesVelocity = 18.0<widget/hour>
7 let salesInTime hours= (salesVelocity * hours)
8
9 printfn “%f” (float (salesInTime 72.0<hour>))
You can use more sophisticated logic to determine to salesVelocity and so on. My goal isn’t to belabor the point. widgets/case, defects/hour, phone calls/second, all are units that you will use in your non-scientific, line of business applications. I sense something that may allow for better accuracy and remove another class of error from applications. I haven’t seen this example used yet by others talking about Measure. I’m trying to look beyond science and see the benefits in other types of calculations.