【问题标题】:Generic units in F#F# 中的通用单位
【发布时间】:2015-05-01 10:59:20
【问题描述】:

在 F# 中编写泛型函数时,我可以使用 LanguagePrimitives 模块中定义的成员,例如在这个函数中,它只是增加一个数字

let inline increment (x : 'a) =
    x + LanguagePrimitives.GenericOne

我想知道是否有任何类似于使用计量单位的方法。特别是:是否可以编写一个接受泛型参数并将其转换为具有单位的相同类型的数字的函数。比如:

let inline toNumberWithUnit<[<Measure>] 'u> x =
    x * GenericOne<'u> //that won't work

这将有一个类型:'a -> 'a。有可能吗?

【问题讨论】:

    标签: generics f# units-of-measurement


    【解决方案1】:

    该签名在 .NET 中是非法的,因此唯一的方法是使用带有静态约束的 F# 内联功能。

    然后你可以这样定义一个函数:

    [<Measure>]
    type M = class end
    
    let x = LanguagePrimitives.FloatWithMeasure<M> 2. 
    
    type T<[<Measure>]'M>() =
        static member ($) (T, x) = LanguagePrimitives.FloatWithMeasure<'M> x
        static member ($) (T, x) = LanguagePrimitives.Float32WithMeasure<'M> x
        static member ($) (T, x) = LanguagePrimitives.Int32WithMeasure<'M> x
        // more overloads
    
    let inline NumberWithMeasure x = T() $ x
    
    let a: float<M>   = NumberWithMeasure 2.
    let b: float32<M> = NumberWithMeasure 2.0f
    let c: int<M>     = NumberWithMeasure 2
    

    处理泛型数字和度量单位时的主要问题是,您最终会得到那些具有泛型类型和类型参数(higher kind)的签名,目前 .NET 不支持这些签名.

    更新

    过了一会儿,我也遇到了这种情况,发现这个答案恰好来自我:)

    在尝试使用不同的度量单位后,我意识到它不起作用,因为类型推断不能概括度量单位,发布的示例有效,因为类型推断见证了 M 度量的使用,然后专门针对M 的函数。

    但是,通过显式使用上面定义的$ 运算符,这是一种使其工作的方法:

    [<Measure>] type km
    [<Measure>] type miles
    
    type WithMeasure<[<Measure>]'M>() =
        static member ($) (x, T) = LanguagePrimitives.FloatWithMeasure<'M> x
        static member ($) (x, T) = LanguagePrimitives.Float32WithMeasure<'M> x
        static member ($) (x, T) = LanguagePrimitives.Int32WithMeasure<'M> x
        static member ($) (x, T) = LanguagePrimitives.DecimalWithMeasure<'M> x
        static member ($) (x, T) = LanguagePrimitives.Int16WithMeasure<'M> x
        static member ($) (x, T) = LanguagePrimitives.Int64WithMeasure<'M> x
        static member ($) (x, T) = LanguagePrimitives.SByteWithMeasure<'M> x
        // no more overloads
    
    
    let a: float<km>      = 2.   $WithMeasure()
    let b: float32<miles> = 2.0f $WithMeasure()
    

    可能有一种方法可以创建泛型函数或泛型常量,但目前似乎无法使用当前版本的 F#。

    我会在 F# 4.1 准备好后尝试它。

    【讨论】:

    • 所以我不能有一个通用函数,而是一个函数序列,需要明确我想使用哪个函数。好吧 - 仍然不是我想要的,但正如你所说,这是我目前能得到的最好的,它一定足够了。非常感谢,先生 :)。
    猜你喜欢
    • 2010-10-02
    • 2010-10-04
    • 2018-06-15
    • 1970-01-01
    • 2016-05-17
    • 2012-07-05
    • 2013-03-12
    • 2011-02-09
    • 2016-01-31
    相关资源
    最近更新 更多