f#泛型类型上的泛型单位
是否可以定义一个通用于数据类型和度量单位的函数?例如,我想做什么,但没有编译(虽然即使没有度量单位也不会,但我相信我表达了我想做的事情): 我知道,对于这个特殊情况,我可以使用f#泛型类型上的泛型单位,f#,units-of-measurement,F#,Units Of Measurement,是否可以定义一个通用于数据类型和度量单位的函数?例如,我想做什么,但没有编译(虽然即使没有度量单位也不会,但我相信我表达了我想做的事情): 我知道,对于这个特殊情况,我可以使用 let dropUnit (x : float<_>) = (float) x 让dropUnit(x:float)=(float)x 但是在写上述内容时,我开始思考一般情况。关于如何编写isValidUnitValue函数的具体问题,答案是: let inline isValidUnitValue my
let dropUnit (x : float<_>) = (float) x
让dropUnit(x:float)=(float)x
但是在写上述内容时,我开始思考一般情况。关于如何编写
isValidUnitValue
函数的具体问题,答案是:
let inline isValidUnitValue myUnit = myUnit > LanguagePrimitives.GenericZero
所以你不需要定义一个歧视性的联盟
关于最初的问题,是否可以定义一个既通用于数据类型又通用于度量单位(如dropUnit
)的函数,简短的回答是否定的。如果存在这样的函数,它将有一个签名,如'a`)=
让ux=x*(LanguagePrimitives.GenericOne:'Num)
重新键入x:'Num
这类似于2),但不需要类型注释。其局限性在于它仅适用于数字类型,但通常情况下,这是计量单位的使用情况。另一种选择是使用内联函数来伪造接口。
let isValidUnitValue myUnit =
match myUnit with
| Weight(x) -> (dropUnit x) > 0.
| Volume(x) -> (dropUnit x) > 0.
let dropUnit (x : float<_>) = (float) x
let inline isValidUnitValue myUnit = myUnit > LanguagePrimitives.GenericZero
type UnitDropper =
static member drop (x:sbyte<_> ) = sbyte x
static member drop (x:int16<_> ) = int16 x
static member drop (x:int<_> ) = int x
static member drop (x:int64<_> ) = int64 x
static member drop (x:decimal<_>) = decimal x
static member drop (x:float32<_>) = float32 x
static member drop (x:float<_> ) = float x
[<Measure>] type m
let x = UnitDropper.drop 2<m> + 3
> let inline dropUnitAndAdd3 x = UnitDropper.drop x + 3 ;;
-> error FS0041: A unique overload for method 'drop' could not be determined ...
let inline retype (x:'a) : 'b = (# "" x : 'b #)
[<Measure>] type m
let x = retype 2<m> + 3
let inline dropUnitAndAdd3 x = retype x + 3
let y = retype 2.0<m> + 3
type DropUnit = DropUnit with
static member ($) (DropUnit, x:sbyte<_> ) = sbyte x
static member ($) (DropUnit, x:int16<_> ) = int16 x
static member ($) (DropUnit, x:int<_> ) = int x
static member ($) (DropUnit, x:int64<_> ) = int64 x
static member ($) (DropUnit, x:decimal<_>) = decimal x
static member ($) (DropUnit, x:float32<_>) = float32 x
static member ($) (DropUnit, x:float<_> ) = float x
let inline dropUnit x = DropUnit $ x
[<Measure>] type m
let x = dropUnit 2<m> + 3
let inline dropUnitAndAdd3 x = dropUnit x + 3
let y = dropUnit 2.0<m> + 3 //fails at compile-time
type MyNumericType<[<Measure 'U>]> =
...
static member dropUoM (x:MyNumericType<_>) : MyNumericType = ...
static member ($) (DropUnit, x:MyNumericType<_>) = MyNumericType.dropUoM(x)
let inline retype (x: 'T) : 'U = (# "" x: 'U #)
let inline stripUoM (x: '``Num<'M>``) =
let _ = x * (LanguagePrimitives.GenericOne : 'Num)
retype x :'Num