Units of Measure in F#
Denis Koroskin
2korden at gmail.com
Tue Oct 7 12:26:24 PDT 2008
On Tue, 07 Oct 2008 22:39:10 +0400, BCS <ao at pathlink.com> wrote:
> Reply to bearophile,
>
>> BCS:
>>
>>> svn.dsource.org seems to be having problmes or I'd post a system I
>>> just
>>> put together.
>>> total code, WS comments: ~ 400 LOC
>>> supports 44 different units,
>>> support +,-,* and / as well as pow and root
>> A lot of work. Does is use a (syntax) strategy similar to this?
>> http://www.boost.org/doc/libs/1_36_0/doc/html/boost_units.html
>> Now D just needs a pow infix operator (** ?) and that's done :-)
>> Bye,
>> bearophile
>
> SVN is working again (or I'm somewhere it works from)
>
> http://www.dsource.org/projects/scrapple/browser/trunk/units/
>
> take a look at si.d first as it's the most useful intro (look way down
> at the bottom)
>
>
Well, I have done it completely different. Here is my (simplified) class
hierarchy from memory:
// Unit is 's', 'kg', 'n' etc, i.e. they are basic orthogonal units
class Unit(string name)
{
enum AsString = name;
}
// A Powered Unit :) PUnit is s^2, kg^(-3.14) etc.
// It is
class PUnit(Unit, float power)
{
alias UnitType Unit;
enum Power = power;
}
// Quantity consists of a unique set of PUnits and a value. It also
// defines a set of operations like opMul, opDiv, opAdd and opSub
// Example: 5 m/s^2
class Quantity(U...)
{
alias Units U;
private float value;
// here is how my opMul looks like:
Multiply!(Units, OtherUnits) opMul(OtherUnits)(OtherUnits other)
{
Multiply!(Units, OtherUnits) result = void;
result.value = value * other.value;
return result;
}
}
here is how I merge Units for multiplication:
template GetUnitPower(Unit, Units...)
{
static if (Units.length == 0) {
enum GetUnitPower = 0;
} else static if (is (Units[0].UnitType == Unit)) {
enum GetUnitPower = Units[0].Power;
} else {
enum GetUnitPower = GetUnitPower!(Unit, Units[1..$]);
}
}
template AddPowers(Unit, Units...)
{
// GetUnitPower returns 0 if there is no such Unit in Units
// put '-' for Divide! here
enum Power = Unit.Power + GetUnitPower!(Unit.UnitType, Units);
// get all the Units without Unit
alias Without!(Unit.UnitType, Units) Rest;
// Add the Unit with a new Power to the list of rest units
alias Tuple!(PUnit!(Unit.UnitType, Power), Rest) Result;
}
As a result you can have any arbitrary amount of orthogonal Units. Add
them with a single line:
mixin(defineUnit("Time", "s"));
mixin(defineUnit("Mass", "kg"));
mixin(defineUnit("Distance", "m"));
mixin(defineUnit("Speed", "m/s"));
Distance d = 6 * m;
Time t = 3 * s;
Speed s = d / t;
More information about the Digitalmars-d
mailing list