3 people like it.
Like the snippet!
Generalized Units of Measure Revisited (using method overloading)
An approach to using annotated types in F# using overloaded methods.
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
|
#nowarn "42"
open System
[<MeasureAnnotatedAbbreviation>] type bool<[<Measure>] 'm> = bool
[<MeasureAnnotatedAbbreviation>] type uint64<[<Measure>] 'm> = uint64
[<MeasureAnnotatedAbbreviation>] type Guid<[<Measure>] 'm> = Guid
[<MeasureAnnotatedAbbreviation>] type string<[<Measure>] 'm> = string
[<MeasureAnnotatedAbbreviation>] type TimeSpan<[<Measure>] 'm> = TimeSpan
[<MeasureAnnotatedAbbreviation>] type DateTime<[<Measure>] 'm> = DateTime
[<MeasureAnnotatedAbbreviation>] type DateTimeOffset<[<Measure>] 'm> = DateTimeOffset
module private Unsafe =
let inline cast<'a, 'b> (a : 'a) : 'b = (# "" a : 'b #)
type UnitOfMeasure =
static member inline tag<[<Measure>]'m> (x : bool) : bool<'m> = Unsafe.cast x
static member inline tag<[<Measure>]'m> (x : int) : int<'m> = Unsafe.cast x
static member inline tag<[<Measure>]'m> (x : int64) : int64<'m> = Unsafe.cast x
static member inline tag<[<Measure>]'m> (x : uint64) : uint64<'m> = Unsafe.cast x
static member inline tag<[<Measure>]'m> (x : float) : float<'m> = Unsafe.cast x
static member inline tag<[<Measure>]'m> (x : decimal) : decimal<'m> = Unsafe.cast x
static member inline tag<[<Measure>]'m> (x : Guid) : Guid<'m> = Unsafe.cast x
static member inline tag<[<Measure>]'m> (x : string) : string<'m> = Unsafe.cast x
static member inline tag<[<Measure>]'m> (x : TimeSpan) : TimeSpan<'m> = Unsafe.cast x
static member inline tag<[<Measure>]'m> (x : DateTime) : DateTime<'m> = Unsafe.cast x
static member inline tag<[<Measure>]'m> (x : DateTimeOffset) : DateTimeOffset<'m> = Unsafe.cast x
static member inline untag<[<Measure>]'m> (x : bool<'m>) : bool = Unsafe.cast x
static member inline untag<[<Measure>]'m> (x : int<'m>) : int = Unsafe.cast x
static member inline untag<[<Measure>]'m> (x : int64<'m>) : int64 = Unsafe.cast x
static member inline untag<[<Measure>]'m> (x : uint64<'m>) : uint64 = Unsafe.cast x
static member inline untag<[<Measure>]'m> (x : float<'m>) : float = Unsafe.cast x
static member inline untag<[<Measure>]'m> (x : decimal<'m>) : decimal = Unsafe.cast x
static member inline untag<[<Measure>]'m> (x : Guid<'m>) : Guid = Unsafe.cast x
static member inline untag<[<Measure>]'m> (x : string<'m>) : string = Unsafe.cast x
static member inline untag<[<Measure>]'m> (x : TimeSpan<'m>) : TimeSpan = Unsafe.cast x
static member inline untag<[<Measure>]'m> (x : DateTime<'m>) : DateTime = Unsafe.cast x
static member inline untag<[<Measure>]'m> (x : DateTimeOffset<'m>) : DateTimeOffset = Unsafe.cast x
static member inline cast<[<Measure>]'m1, [<Measure>]'m2> (x : bool<'m1>) : bool<'m2> = Unsafe.cast x
static member inline cast<[<Measure>]'m1, [<Measure>]'m2> (x : int<'m1>) : int<'m2> = Unsafe.cast x
static member inline cast<[<Measure>]'m1, [<Measure>]'m2> (x : int64<'m1>) : int64<'m2> = Unsafe.cast x
static member inline cast<[<Measure>]'m1, [<Measure>]'m2> (x : uint64<'m1>) : uint64<'m2> = Unsafe.cast x
static member inline cast<[<Measure>]'m1, [<Measure>]'m2> (x : float<'m1>) : float<'m2> = Unsafe.cast x
static member inline cast<[<Measure>]'m1, [<Measure>]'m2> (x : decimal<'m1>) : decimal<'m2> = Unsafe.cast x
static member inline cast<[<Measure>]'m1, [<Measure>]'m2> (x : Guid<'m1>) : Guid<'m2> = Unsafe.cast x
static member inline cast<[<Measure>]'m1, [<Measure>]'m2> (x : string<'m1>) : string<'m2> = Unsafe.cast x
static member inline cast<[<Measure>]'m1, [<Measure>]'m2> (x : TimeSpan<'m1>) : TimeSpan<'m2> = Unsafe.cast x
static member inline cast<[<Measure>]'m1, [<Measure>]'m2> (x : DateTime<'m1>) : DateTime<'m2> = Unsafe.cast x
static member inline cast<[<Measure>]'m1, [<Measure>]'m2> (x : DateTimeOffset<'m1>) : DateTimeOffset<'m2> = Unsafe.cast x
|
1:
2:
3:
4:
5:
6:
|
[<Measure>] type m
[<Measure>] type n
let x = UnitOfMeasure.tag<m> "string"
let y = UnitOfMeasure.cast<m,n> x
let z = UnitOfMeasure.untag y
|
namespace System
Multiple items
type MeasureAnnotatedAbbreviationAttribute =
inherit Attribute
new : unit -> MeasureAnnotatedAbbreviationAttribute
Full name: Microsoft.FSharp.Core.MeasureAnnotatedAbbreviationAttribute
--------------------
new : unit -> MeasureAnnotatedAbbreviationAttribute
Multiple items
type bool = Boolean
Full name: Microsoft.FSharp.Core.bool
--------------------
type bool<'m> = bool
Full name: Script.bool<_>
Multiple items
type MeasureAttribute =
inherit Attribute
new : unit -> MeasureAttribute
Full name: Microsoft.FSharp.Core.MeasureAttribute
--------------------
new : unit -> MeasureAttribute
Multiple items
val uint64 : value:'T -> uint64 (requires member op_Explicit)
Full name: Microsoft.FSharp.Core.Operators.uint64
--------------------
type uint64 = UInt64
Full name: Microsoft.FSharp.Core.uint64
--------------------
type uint64<'m> = uint64
Full name: Script.uint64<_>
Multiple items
type Guid =
struct
new : b:byte[] -> Guid + 4 overloads
member CompareTo : value:obj -> int + 1 overload
member Equals : o:obj -> bool + 1 overload
member GetHashCode : unit -> int
member ToByteArray : unit -> byte[]
member ToString : unit -> string + 2 overloads
static val Empty : Guid
static member NewGuid : unit -> Guid
static member Parse : input:string -> Guid
static member ParseExact : input:string * format:string -> Guid
...
end
Full name: System.Guid
--------------------
type Guid<'m> = Guid
Full name: Script.Guid<_>
--------------------
Guid()
Guid(b: byte []) : unit
Guid(g: string) : unit
Guid(a: int, b: int16, c: int16, d: byte []) : unit
Guid(a: uint32, b: uint16, c: uint16, d: byte, e: byte, f: byte, g: byte, h: byte, i: byte, j: byte, k: byte) : unit
Guid(a: int, b: int16, c: int16, d: byte, e: byte, f: byte, g: byte, h: byte, i: byte, j: byte, k: byte) : unit
Multiple items
val string : value:'T -> string
Full name: Microsoft.FSharp.Core.Operators.string
--------------------
type string = String
Full name: Microsoft.FSharp.Core.string
--------------------
type string<'m> = string
Full name: Script.string<_>
Multiple items
type TimeSpan =
struct
new : ticks:int64 -> TimeSpan + 3 overloads
member Add : ts:TimeSpan -> TimeSpan
member CompareTo : value:obj -> int + 1 overload
member Days : int
member Duration : unit -> TimeSpan
member Equals : value:obj -> bool + 1 overload
member GetHashCode : unit -> int
member Hours : int
member Milliseconds : int
member Minutes : int
...
end
Full name: System.TimeSpan
--------------------
type TimeSpan<'m> = TimeSpan
Full name: Script.TimeSpan<_>
--------------------
TimeSpan()
TimeSpan(ticks: int64) : unit
TimeSpan(hours: int, minutes: int, seconds: int) : unit
TimeSpan(days: int, hours: int, minutes: int, seconds: int) : unit
TimeSpan(days: int, hours: int, minutes: int, seconds: int, milliseconds: int) : unit
Multiple items
type DateTime =
struct
new : ticks:int64 -> DateTime + 10 overloads
member Add : value:TimeSpan -> DateTime
member AddDays : value:float -> DateTime
member AddHours : value:float -> DateTime
member AddMilliseconds : value:float -> DateTime
member AddMinutes : value:float -> DateTime
member AddMonths : months:int -> DateTime
member AddSeconds : value:float -> DateTime
member AddTicks : value:int64 -> DateTime
member AddYears : value:int -> DateTime
...
end
Full name: System.DateTime
--------------------
type DateTime<'m> = DateTime
Full name: Script.DateTime<_>
--------------------
DateTime()
(+0 other overloads)
DateTime(ticks: int64) : unit
(+0 other overloads)
DateTime(ticks: int64, kind: DateTimeKind) : unit
(+0 other overloads)
DateTime(year: int, month: int, day: int) : unit
(+0 other overloads)
DateTime(year: int, month: int, day: int, calendar: Globalization.Calendar) : unit
(+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int) : unit
(+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, kind: DateTimeKind) : unit
(+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, calendar: Globalization.Calendar) : unit
(+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int) : unit
(+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int, kind: DateTimeKind) : unit
(+0 other overloads)
Multiple items
type DateTimeOffset =
struct
new : dateTime:DateTime -> DateTimeOffset + 5 overloads
member Add : timeSpan:TimeSpan -> DateTimeOffset
member AddDays : days:float -> DateTimeOffset
member AddHours : hours:float -> DateTimeOffset
member AddMilliseconds : milliseconds:float -> DateTimeOffset
member AddMinutes : minutes:float -> DateTimeOffset
member AddMonths : months:int -> DateTimeOffset
member AddSeconds : seconds:float -> DateTimeOffset
member AddTicks : ticks:int64 -> DateTimeOffset
member AddYears : years:int -> DateTimeOffset
...
end
Full name: System.DateTimeOffset
--------------------
type DateTimeOffset<'m> = DateTimeOffset
Full name: Script.DateTimeOffset<_>
--------------------
DateTimeOffset()
DateTimeOffset(dateTime: DateTime) : unit
DateTimeOffset(ticks: int64, offset: TimeSpan) : unit
DateTimeOffset(dateTime: DateTime, offset: TimeSpan) : unit
DateTimeOffset(year: int, month: int, day: int, hour: int, minute: int, second: int, offset: TimeSpan) : unit
DateTimeOffset(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int, offset: TimeSpan) : unit
DateTimeOffset(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int, calendar: Globalization.Calendar, offset: TimeSpan) : unit
val private cast : a:'a -> 'b
Full name: Script.Unsafe.cast
val a : 'a
type UnitOfMeasure =
static member cast : x:bool<'m1> -> bool<'m2>
static member cast : x:int<'m1> -> int<'m2>
static member cast : x:int64<'m1> -> int64<'m2>
static member cast : x:uint64<'m1> -> uint64<'m2>
static member cast : x:float<'m1> -> float<'m2>
static member cast : x:decimal<'m1> -> decimal<'m2>
static member cast : x:Guid<'m1> -> Guid<'m2>
static member cast : x:string<'m1> -> string<'m2>
static member cast : x:TimeSpan<'m1> -> TimeSpan<'m2>
static member cast : x:DateTime<'m1> -> DateTime<'m2>
...
Full name: Script.UnitOfMeasure
static member UnitOfMeasure.tag : x:bool -> bool<'m>
Full name: Script.UnitOfMeasure.tag
val x : bool
module Unsafe
from Script
static member UnitOfMeasure.tag : x:int -> int<'m>
Full name: Script.UnitOfMeasure.tag
val x : int
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<_>
static member UnitOfMeasure.tag : x:int64 -> int64<'m>
Full name: Script.UnitOfMeasure.tag
val x : int64
Multiple items
val int64 : value:'T -> int64 (requires member op_Explicit)
Full name: Microsoft.FSharp.Core.Operators.int64
--------------------
type int64 = Int64
Full name: Microsoft.FSharp.Core.int64
--------------------
type int64<'Measure> = int64
Full name: Microsoft.FSharp.Core.int64<_>
static member UnitOfMeasure.tag : x:uint64 -> uint64<'m>
Full name: Script.UnitOfMeasure.tag
val x : uint64
static member UnitOfMeasure.tag : x:float -> float<'m>
Full name: Script.UnitOfMeasure.tag
val x : float
Multiple items
val float : value:'T -> float (requires member op_Explicit)
Full name: Microsoft.FSharp.Core.Operators.float
--------------------
type float = Double
Full name: Microsoft.FSharp.Core.float
--------------------
type float<'Measure> = float
Full name: Microsoft.FSharp.Core.float<_>
static member UnitOfMeasure.tag : x:decimal -> decimal<'m>
Full name: Script.UnitOfMeasure.tag
val x : decimal
Multiple items
val decimal : value:'T -> decimal (requires member op_Explicit)
Full name: Microsoft.FSharp.Core.Operators.decimal
--------------------
type decimal = Decimal
Full name: Microsoft.FSharp.Core.decimal
--------------------
type decimal<'Measure> = decimal
Full name: Microsoft.FSharp.Core.decimal<_>
static member UnitOfMeasure.tag : x:Guid -> Guid<'m>
Full name: Script.UnitOfMeasure.tag
val x : Guid
static member UnitOfMeasure.tag : x:string -> string<'m>
Full name: Script.UnitOfMeasure.tag
val x : string
static member UnitOfMeasure.tag : x:TimeSpan -> TimeSpan<'m>
Full name: Script.UnitOfMeasure.tag
val x : TimeSpan
static member UnitOfMeasure.tag : x:DateTime -> DateTime<'m>
Full name: Script.UnitOfMeasure.tag
val x : DateTime
static member UnitOfMeasure.tag : x:DateTimeOffset -> DateTimeOffset<'m>
Full name: Script.UnitOfMeasure.tag
val x : DateTimeOffset
static member UnitOfMeasure.untag : x:bool<'m> -> bool
Full name: Script.UnitOfMeasure.untag
val x : bool<'m>
static member UnitOfMeasure.untag : x:int<'m> -> int
Full name: Script.UnitOfMeasure.untag
val x : int<'m>
static member UnitOfMeasure.untag : x:int64<'m> -> int64
Full name: Script.UnitOfMeasure.untag
val x : int64<'m>
static member UnitOfMeasure.untag : x:uint64<'m> -> uint64
Full name: Script.UnitOfMeasure.untag
val x : uint64<'m>
static member UnitOfMeasure.untag : x:float<'m> -> float
Full name: Script.UnitOfMeasure.untag
val x : float<'m>
static member UnitOfMeasure.untag : x:decimal<'m> -> decimal
Full name: Script.UnitOfMeasure.untag
val x : decimal<'m>
static member UnitOfMeasure.untag : x:Guid<'m> -> Guid
Full name: Script.UnitOfMeasure.untag
val x : Guid<'m>
static member UnitOfMeasure.untag : x:string<'m> -> string
Full name: Script.UnitOfMeasure.untag
val x : string<'m>
static member UnitOfMeasure.untag : x:TimeSpan<'m> -> TimeSpan
Full name: Script.UnitOfMeasure.untag
val x : TimeSpan<'m>
static member UnitOfMeasure.untag : x:DateTime<'m> -> DateTime
Full name: Script.UnitOfMeasure.untag
val x : DateTime<'m>
static member UnitOfMeasure.untag : x:DateTimeOffset<'m> -> DateTimeOffset
Full name: Script.UnitOfMeasure.untag
val x : DateTimeOffset<'m>
static member UnitOfMeasure.cast : x:bool<'m1> -> bool<'m2>
Full name: Script.UnitOfMeasure.cast
val x : bool<'m1>
static member UnitOfMeasure.cast : x:int<'m1> -> int<'m2>
Full name: Script.UnitOfMeasure.cast
val x : int<'m1>
static member UnitOfMeasure.cast : x:int64<'m1> -> int64<'m2>
Full name: Script.UnitOfMeasure.cast
val x : int64<'m1>
static member UnitOfMeasure.cast : x:uint64<'m1> -> uint64<'m2>
Full name: Script.UnitOfMeasure.cast
val x : uint64<'m1>
static member UnitOfMeasure.cast : x:float<'m1> -> float<'m2>
Full name: Script.UnitOfMeasure.cast
val x : float<'m1>
static member UnitOfMeasure.cast : x:decimal<'m1> -> decimal<'m2>
Full name: Script.UnitOfMeasure.cast
val x : decimal<'m1>
static member UnitOfMeasure.cast : x:Guid<'m1> -> Guid<'m2>
Full name: Script.UnitOfMeasure.cast
val x : Guid<'m1>
static member UnitOfMeasure.cast : x:string<'m1> -> string<'m2>
Full name: Script.UnitOfMeasure.cast
val x : string<'m1>
static member UnitOfMeasure.cast : x:TimeSpan<'m1> -> TimeSpan<'m2>
Full name: Script.UnitOfMeasure.cast
val x : TimeSpan<'m1>
static member UnitOfMeasure.cast : x:DateTime<'m1> -> DateTime<'m2>
Full name: Script.UnitOfMeasure.cast
val x : DateTime<'m1>
static member UnitOfMeasure.cast : x:DateTimeOffset<'m1> -> DateTimeOffset<'m2>
Full name: Script.UnitOfMeasure.cast
val x : DateTimeOffset<'m1>
[<Measure>]
type m
Full name: Script.m
[<Measure>]
type n
Full name: Script.n
val x : string<m>
Full name: Script.x
static member UnitOfMeasure.tag : x:bool -> bool<'m>
(+0 other overloads)
static member UnitOfMeasure.tag : x:int -> int<'m>
(+0 other overloads)
static member UnitOfMeasure.tag : x:int64 -> int64<'m>
(+0 other overloads)
static member UnitOfMeasure.tag : x:uint64 -> uint64<'m>
(+0 other overloads)
static member UnitOfMeasure.tag : x:float -> float<'m>
(+0 other overloads)
static member UnitOfMeasure.tag : x:decimal -> decimal<'m>
(+0 other overloads)
static member UnitOfMeasure.tag : x:Guid -> Guid<'m>
(+0 other overloads)
static member UnitOfMeasure.tag : x:string -> string<'m>
(+0 other overloads)
static member UnitOfMeasure.tag : x:TimeSpan -> TimeSpan<'m>
(+0 other overloads)
static member UnitOfMeasure.tag : x:DateTime -> DateTime<'m>
(+0 other overloads)
val y : string<n>
Full name: Script.y
static member UnitOfMeasure.cast : x:bool<'m1> -> bool<'m2>
(+0 other overloads)
static member UnitOfMeasure.cast : x:int<'m1> -> int<'m2>
(+0 other overloads)
static member UnitOfMeasure.cast : x:int64<'m1> -> int64<'m2>
(+0 other overloads)
static member UnitOfMeasure.cast : x:uint64<'m1> -> uint64<'m2>
(+0 other overloads)
static member UnitOfMeasure.cast : x:float<'m1> -> float<'m2>
(+0 other overloads)
static member UnitOfMeasure.cast : x:decimal<'m1> -> decimal<'m2>
(+0 other overloads)
static member UnitOfMeasure.cast : x:Guid<'m1> -> Guid<'m2>
(+0 other overloads)
static member UnitOfMeasure.cast : x:string<'m1> -> string<'m2>
(+0 other overloads)
static member UnitOfMeasure.cast : x:TimeSpan<'m1> -> TimeSpan<'m2>
(+0 other overloads)
static member UnitOfMeasure.cast : x:DateTime<'m1> -> DateTime<'m2>
(+0 other overloads)
val z : string
Full name: Script.z
static member UnitOfMeasure.untag : x:bool<'m> -> bool
(+0 other overloads)
static member UnitOfMeasure.untag : x:int<'m> -> int
(+0 other overloads)
static member UnitOfMeasure.untag : x:int64<'m> -> int64
(+0 other overloads)
static member UnitOfMeasure.untag : x:uint64<'m> -> uint64
(+0 other overloads)
static member UnitOfMeasure.untag : x:float<'m> -> float
(+0 other overloads)
static member UnitOfMeasure.untag : x:decimal<'m> -> decimal
(+0 other overloads)
static member UnitOfMeasure.untag : x:Guid<'m> -> Guid
(+0 other overloads)
static member UnitOfMeasure.untag : x:string<'m> -> string
(+0 other overloads)
static member UnitOfMeasure.untag : x:TimeSpan<'m> -> TimeSpan
(+0 other overloads)
static member UnitOfMeasure.untag : x:DateTime<'m> -> DateTime
(+0 other overloads)
More information