5 people like it.

General power function with units

The snippet demonstrates how to write a general power function that has correct type involving units-of-measure. The function uses numbers represented using types. The snippet is mainly an example of what can be done (not recommended for the real world).

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
[<Measure>] type cm

// Represents a number with units of measure powered to the
// number's value (e.g "(S (S O))" has type Num<cm, cm^3>)
type Num<[<Measure>] 'M, [<Measure>] 'N> = 
  | O_ of int * float<'N>
  | S_ of int * Num<'M, 'N / 'M>

// Constructors that hide that simplify the creation  
let O : Num<'M, 'M> = O_ (1, 0.0<_>)
let S n = match n with O_(i, _) | S_(i, _) -> S_(i + 1, n)

// Type-safe power function with units of measure
let pow (x:float<'M>) ((O_(i, _) | S_(i, _)):Num<'M, 'M 'N>) : float<'M 'N> =
  // Unsafe hacky implementation, which is hidden
  // from the user (for simplicity)
  unbox ((float x) ** float i)

let res = pow 2.0<cm> (S (S O))
Multiple items
type MeasureAttribute =
  inherit Attribute
  new : unit -> MeasureAttribute

Full name: Microsoft.FSharp.Core.MeasureAttribute

--------------------
new : unit -> MeasureAttribute
[<Measure>]
type cm

Full name: Script.cm
type Num<'M,'N> =
  | O_ of int * float<'N>
  | S_ of int * Num<'M,'N/'M>

Full name: Script.Num<_,_>
union case Num.O_: int * float<'N> -> Num<'M,'N>
Multiple items
val int : value:'T -> int (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.int

--------------------
type int = int32

Full name: Microsoft.FSharp.Core.int

--------------------
type int<'Measure> = int

Full name: Microsoft.FSharp.Core.int<_>
Multiple items
val float : value:'T -> float (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.float

--------------------
type float = System.Double

Full name: Microsoft.FSharp.Core.float

--------------------
type float<'Measure> = float

Full name: Microsoft.FSharp.Core.float<_>
union case Num.S_: int * Num<'M,'N/'M> -> Num<'M,'N>
val O : Num<'M,'M>

Full name: Script.O
val S : n:Num<'u,'v> -> Num<'u,'u 'v>

Full name: Script.S
val n : Num<'u,'v>
val i : int
val pow : x:float<'M> -> Num<'M,'N> -> float<'N>

Full name: Script.pow
val x : float<'M>
val unbox : value:obj -> 'T

Full name: Microsoft.FSharp.Core.Operators.unbox
val res : float<cm ^ 3>

Full name: Script.res

More information

Link:http://fssnip.net/4H
Posted:5 years ago
Author:Tomas Petricek
Tags: fsharp , types , units , units of measure