2012-03-07 9 views
2

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

ответ

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 
+0

Спасибо за идею Единственным недостатком является то, у нас есть разные. имя функции для аналогичной задачи. – qehgt

+0

Существует только одна функция 'storeArray'. Дублирование: вы всегда передаете 'StoreOps.store', когда вы вызываете функцию' storeArray'. – pad

+0

Я имею в виду, что у нас есть 'StoreOps.store' для' float' и 'StoreOps.storeArray' для' float [] '. В идеальном мире должен быть только «StoreOps.store» – qehgt

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..., если вы не хотите подвергаться

+0

Ницца, но выглядит как код Александреску – qehgt

+0

скорее уродливым углом лангажа, чем собственно рубить. довольно уродливый, хотя;) – nicolas

2

You может сделать это таким образом:.

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 

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

+0

Спасибо, я попробую это тоже. – qehgt

Смежные вопросы