F#中的泛型函数

时间:2012-03-07 15:34:35

标签: f#

我正在编写某种序列化库(用于学习F#)。现在我坚持这个:

假设我们已经有一些基本类型的序列化函数:

type StoreOps =
    static member inline store(x:int) = ...
    static member inline store(x:int64) = ...
    static member inline store(x:float) = ...
    static member inline store(x:float32) = ...
    static member inline store(x:bool) = ...
    static member inline store(x:string) = ...
    ....

现在我想实现泛型函数来存储任何基本类型数组:

let inline store(x:'T[]) = 
        x |> Array.iter StoreOps.store

,但编译器无法编译它(错误消息显示:A unique overload for method 'store' could not be determined based on type information prior to this program point)。

在F#中实现此类功能的正确方法是什么?因为我不想为int[]bool[]float[]复制粘贴N个相等的函数...

3 个答案:

答案 0 :(得分:4)

首先,对于采用特定类型参数的定义,您可能不需要inline。其次,简短的回答可能是“没有好办法”。但是,如果你愿意忍受可怕的黑客行为,你可以做类似的事情:

type StoreOps = 
    ... // everything you've currently got

let inline storeArray< ^t, ^u when (^t or ^u) : (static member store : ^u -> unit)> arr = 
    arr 
    |> Array.iter (fun x -> ((^t or ^u) : (static member store : ^u -> unit) x))

type StoreOps with
    static member inline store arr = storeArray<StoreOps,_> arr

如果您不希望公开storeArray,也可以let inline private storeArray...帮助私有(使用{{1}}。

答案 1 :(得分:3)

一种解决方法是将store函数作为参数传递给泛型函数:

type StoreOps =
    static member inline store (x: int) = ...
    static member inline store (x: int64) = ...
    static member inline store (x: float) = ...
    static member inline store (x: float32) = ...
    static member inline store (x: bool) = ...
    static member inline store (x: string) = ...

    static member storeArray xs f =
        xs |> Array.iter f
    ....

// The compiler chooses the right overload based on types of array elements
StoreOps.storeArray [|100; 200|] StoreOps.store
StoreOps.storeArray [|100L; 200L|] StoreOps.store

答案 2 :(得分:2)

你可以这样做:

type StoreOps = StoreOps with
    static member ($) (StoreOps,x:int)     = (* code for storing *) ()
    static member ($) (StoreOps,x:int64)   = (* code for storing *) ()
    static member ($) (StoreOps,x:float)   = (* code for storing *) ()
    static member ($) (StoreOps,x:float32) = (* code for storing *) ()
    static member ($) (StoreOps,x:bool)    = (* code for storing *) ()
    static member ($) (StoreOps,x:string)  = (* code for storing *) ()

let inline store(x:_[]) = Array.iter (fun a -> StoreOps $ a) x

它会自动为您生成约束。