универсальная функция в F # - PullRequest
2 голосов
/ 07 марта 2012

Я пишу какую-то библиотеку сериализации (для изучения 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 #? Потому что я не хочу копировать и вставлять N одинаковых функций для int[], bool[], float[] ...

Ответы [ 3 ]

4 голосов
/ 07 марта 2012

Прежде всего, вам, вероятно, не нужно 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..., если вы не хотите, чтобы он был открыт.

3 голосов
/ 07 марта 2012

Один обходной путь передает 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 голосов
/ 08 марта 2012

Вы можете сделать это следующим образом:

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

Он автоматически сгенерирует для вас ограничения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...