views:

90

answers:

2

I'm trying to write a unit of measure converter. I have defined two units of measure, KWh and MWh & am trying to write a function to convert between the two that will pattern match on the numeric type. so I could have a float, decimal, int of KWh to convert to MWh. I'm not able to figure out how to correctly branch on type when I don't have a obj type.

Ideas?

[<Measure>]
type KWh

[<Measure>]
type MWh

// want to do this, but can't because x is not x:obj, 
// its something like x:float<KWh>
let toMWh x = 
    match x with
    | :? float<KWh>     -> x * (1.0<MWh>/1000.0<KWh>)
    | :? int<KWh>       -> // ...


// above code not valid f#
+3  A: 

Honestly, I'd just do the low-budget overloading solution:

[<Measure>] 
type KWh 

[<Measure>] 
type MWh 

type Convert = 
    static member toMWh (x:float<KWh>) =  x * 1.0<MWh> / 1000.0<KWh>
    static member toMWh (x:int<KWh>) =  x * 1<MWh> / 1000<KWh>

printfn "%d" (int(Convert.toMWh(5000<KWh>)))
printfn "%f" (float(Convert.toMWh(5500.0<KWh>)))

That said, someone may come up with a clever, type-safe way to do it with inline (I'm not sure offhand if it's possible). I would avoid your run-time matching, since it sacrifices static type-safety (which is kinda the point of units). (Also, it is impossible to do run-time matching of units anyway, since units are erased during compilation.)

Brian
A: 

I think this should work

let Convert (val:float<t>) = 
    match t with
    |Mwh -> val*1000
    |Kwh -> val

I don't have the compiler on me to check but this shouldn't be to far off

jpalmer