简体   繁体   English

F#中的泛型函数

[英]generic function in F#

I'm writing some kind of serialization library (for purpose of learning F#). 我正在编写某种序列化库(用于学习F#)。 And now I stuck with this: 现在我坚持这个:

Suppose we already have serialization functions for some basic types: 假设我们已经有一些基本类型的序列化函数:

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) = ...
    ....

Now I want to implement generic function to store any array of basic types: 现在我想实现泛型函数来存储任何基本类型的数组:

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

, but compiler can't compile it (error message says: A unique overload for method 'store' could not be determined based on type information prior to this program point ). ,但编译器无法编译它(错误消息说: A unique overload for method 'store' could not be determined based on type information prior to this program point )。

What is a right way to implement such functions in F#? 在F#中实现这些功能的正确方法是什么? Because I don't want to copy-paste N equal functions for int[] , bool[] , float[] ... 因为我不想为int[]bool[]float[]复制粘贴N个相等的函数...

First of all, you probably don't need inline on the definitions which take arguments of a particular type. 首先,您可能不需要inline带有特定类型参数的定义。 Secondly, the short answer is probably "there's no good way to do that". 其次,简短的回答可能是“没有好办法”。 However, if you're willing to tolerate horrible hacks, you can do something like: 但是,如果你愿意忍受可怕的黑客行为,你可以做以下事情:

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

You can also make the storeArray helper private (using let inline private storeArray... if you don't want it exposed. 您还可以将storeArray助手storeArray私有(使用let inline private storeArray...如果您不希望它暴露。

One workaround is passing store functions as a parameter in a generic function: 一种解决方法是将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

You can do it this way: 你可以这样做:

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

It will generate the constraints for you automatically. 它会自动为您生成约束。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM