【问题标题】:Using numeric generics to get min/max of native numeric types, Int32.MaxValue doesn't appear to exist使用数字泛型获取本机数字类型的最小值/最大值,Int32.MaxValue 似乎不存在
【发布时间】:2016-12-06 15:08:05
【问题描述】:

我需要一个可以访问数字类型的MinValueMaxValue 的数字泛型函数。由于所有 BCL 类型都有这些成员,我想我可以写这样的东西:

let inline zeroOrMax(x: ^a) =
    match x with
    | a when a = LanguagePrimitives.GenericZero -> x
    | a when a = LanguagePrimitives.GenericOne -> 
        let maxVal = (^a: (static member MaxValue : ^a) ())  
        maxVal 
    | a when -a = LanguagePrimitives.GenericOne -> 
        let maxVal = (^a: (static member MaxValue : ^a) ())  
        -maxVal 
    | _ -> ...

此函数将为您提供基础类型的零或(负/正)最大值。

当我创建自己的实现MaxValue 的类型时,可以找到此方法,但是虽然Int32Int64 等具有静态成员MaxValueMinValue,但我不断收到参数没有的静态编译错误已经说过静态成员:

let test (x: int64) =
    // error FS0001: The type 'int64' does not support the operator 'get_MaxValue'
    zeroOrMax x

我认为这是因为 F# 特别对待这些类型。或者也许我只是需要一种不同的语法。有没有办法在保持数值通用性访问基础类型的最小值/最大值的同时解决这个问题?

【问题讨论】:

  • int64.MaxValue 是一个成员常量,而不是一个属性
  • @fyodor 哎哟,dejavu,感觉就像我之前看到的一样。猜猜没有比这更简单的解决方法了吗?
  • 不,没有办法。我在FsControl 中创建了一个generic function,由overloading many different types 执行此操作。您可以使用它或复制那里的代码。
  • @Gustavo,有趣的方法。我在沿着这些思路思考(我希望把一些东西放在一起,猜想这还不会发生)。另一种欺骗系统的方式导致了 F# 的奇怪(或不是?)行为,reported here
  • 有趣的错误报告,一如既往。我将从该通用函数中添加一些代码作为答案。

标签: generics f#


【解决方案1】:

静态解析的类型成员约束不考虑字段。

如 cmets 中所述,您可以使用从 FsControl 创建像 maxValue 这样的通用函数,通过为每个已知类型指定重载来满足您的需求。

这是this fragment of code 的“独立”版本:

open System

type MaxValue = MaxValue with
    static member ($) (_:unit          , _:MaxValue) = ()
    static member ($) (_:bool          , _:MaxValue) = true
    static member ($) (_:char          , _:MaxValue) = Char.MaxValue
    static member ($) (_:byte          , _:MaxValue) = Byte.MaxValue
    static member ($) (_:sbyte         , _:MaxValue) = SByte.MaxValue
    static member ($) (_:float         , _:MaxValue) = Double.MaxValue
    static member ($) (_:int16         , _:MaxValue) = Int16.MaxValue
    static member ($) (_:int           , _:MaxValue) = Int32.MaxValue
    static member ($) (_:int64         , _:MaxValue) = Int64.MaxValue
    static member ($) (_:float32       , _:MaxValue) = Single.MaxValue
    static member ($) (_:uint16        , _:MaxValue) = UInt16.MaxValue
    static member ($) (_:uint32        , _:MaxValue) = UInt32.MaxValue
    static member ($) (_:uint64        , _:MaxValue) = UInt64.MaxValue
    static member ($) (_:decimal       , _:MaxValue) = Decimal.MaxValue
    static member ($) (_:DateTime      , _:MaxValue) = DateTime.MaxValue
    static member ($) (_:DateTimeOffset, _:MaxValue) = DateTimeOffset.MaxValue
    static member ($) (_:TimeSpan      , _:MaxValue) = TimeSpan.MaxValue

let inline maxValue() :'r =  Unchecked.defaultof<'r> $ MaxValue

type MaxValue with
    static member inline ($) ((_:'a*'b         ), _:MaxValue) = maxValue(), maxValue()
    static member inline ($) ((_:'a*'b*'c      ), _:MaxValue) = maxValue(), maxValue(), maxValue()
    static member inline ($) ((_:'a*'b*'c*'d   ), _:MaxValue) = maxValue(), maxValue(), maxValue(), maxValue()
    static member inline ($) ((_:'a*'b*'c*'d*'e), _:MaxValue) = maxValue(), maxValue(), maxValue(), maxValue(), maxValue()

// Usage
let x:int  = maxValue()
// val x : int = 2147483647

let y:int * float *TimeSpan = maxValue()
// val y : int * float * TimeSpan = (2147483647, 1.797693135e+308, 10675199.02:48:05.4775807)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-02
    • 1970-01-01
    • 2011-01-04
    • 1970-01-01
    • 2016-07-24
    相关资源
    最近更新 更多