具有通用参数types的函数

我想弄清楚如何定义一个函数,适用于多种types的参数(如int和int64)。 据我了解,函数重载是不可能在F#(编译器肯定抱怨)。 以下面的function为例。

let sqrt_int = function | n:int -> int (sqrt (float n)) | n:int64 -> int64 (sqrt (float n)) 

编译器当然抱怨语法是无效的(模式匹配中的types约束似乎不被支持),但我认为这说明了我想实现的function:一个函数在多个参数types上运行,并返回一个值types。 我有一种感觉,这是可能的在F#使用genericstypes/types推理/模式匹配的一些组合,但语法躲过了我。 我也尝试使用:? 运算符(dynamictypestesting)和模式匹配块中的子句 ,这仍会产生各种错误。

由于我对这门语言比较陌生,所以我很可能会在这里做一些不可能的事情,所以请让我知道是否有其他解决办法。

重载通常是types推导语言的bug(至less在类似F#的情况下,types系统不足以包含types类)。 在F#中有许多select:

  • 在方法(types的成员)上使用重载,在这种情况下,重载的工作方式与其他.Net语言非常类似(您可以临时重载成员,提供的调用可以通过参数的数量/types进行区分)
  • 在函数上使用“inline”,“^”和静态成员约束来特别重载(这是大多数需要处理int / float /等的各种math运算符;这里的语法很奇怪,这是除了F#库以外,很less使用)
  • 通过传递额外的操作字典参数来模拟types类(这是INumeric在其中一个F#PowerPack库中为一般用于任意用户定义types的各种mathalgorithm而做的)
  • 回到dynamictypes(传入'obj'参数,做一个dynamictypestesting,抛出一个坏的types的运行时exception)

对于你的特定例子,我可能只是使用方法重载:

 type MathOps = static member sqrt_int(x:int) = x |> float |> sqrt |> int static member sqrt_int(x:int64) = x |> float |> sqrt |> int64 let x = MathOps.sqrt_int 9 let y = MathOps.sqrt_int 100L 

是的,这可以做到。 看看这个hubFS线程 。

在这种情况下,解决scheme将是:

 let inline retype (x:'a) : 'b = (# "" x : 'b #) let inline sqrt_int (n:'a) = retype (sqrt (float n)) : 'a 

警告 :没有编译时types检查。 即sqrt_int "blabla"编译好,但你会在运行时得到一个FormatException。

这工作:

 type T = T with static member ($) (T, n:int ) = int (sqrt (float n)) static member ($) (T, n:int64) = int64 (sqrt (float n)) let inline sqrt_int (x:'t) :'t = T $ x 

它使用静态约束和重载,从而对参数的types进行编译时查找。

静态约束是在一个操作符(操作符$ )的情况下自动生成的,但它总是可以用手写入:

 type T = T with static member Sqr (T, n:int ) = int (sqrt (float n)) static member Sqr (T, n:int64) = int64 (sqrt (float n)) let inline sqrt_int (x:'N) :'N = ((^T or ^N) : (static member Sqr: ^T * ^N -> _) T, x) 

更多关于这里 。

这是使用运行时types检查的另一种方法。

 let sqrt_int<'a> (x:'a) : 'a = // ' match box x with | :? int as i -> downcast (i |> float |> sqrt |> int |> box) | :? int64 as i -> downcast (i |> float |> sqrt |> int64 |> box) | _ -> failwith "boo" let a = sqrt_int 9 let b = sqrt_int 100L let c = sqrt_int "foo" // boom 

不要从已经提供的正确答案中拿走,但实际上可以在模式匹配中使用types约束。 语法是:

 | :? type -> 

或者,如果你想结合types检查和铸造:

 | :? type as foo ->