2012-12-24 10 views
8

Chcę zaimplementować IEnumerable<KeyValuePair<DateTime, 'T>> w mojej własnej klasie i dodać operatorów matematyki do tej klasy, aby operatorzy mogli pracować jak funkcja inline na dowolnych numerycznych typach 'T - automatycznie dodawali ograniczenia.f # Statycznie rozdzielone typy w elementach typu

Po prostu nie mogę wykonać następującego kodu. Nie działa on bez słowa kluczowego "inline" w deklaracji członkowskiej.

Ponadto, jeśli zdefiniować funkcję

let inline add l r = l + r 

przed rodzaju i używać go zamiast dodawania l.Value + r.Value, to również nie działa.

Czy ktoś mógłby mi pokazać, co robię źle?

Prawdopodobnie całe podejście jest złe i istnieje sposób na osiągnięcie tego samego celu w inny sposób?

namespace Test 

open System 
open System.Linq 
open System.Collections.Generic 

[<SerializableAttribute>] 
type TimeSeries<'T>(dictionary : IDictionary<DateTime, 'T>) = 
    let internalList = new SortedList<DateTime, 'T>(dictionary) 
    interface IEnumerable<KeyValuePair<DateTime, 'T>> with 
     member this.GetEnumerator() = internalList.GetEnumerator() 
     member this.GetEnumerator() : Collections.IEnumerator 
      = internalList.GetEnumerator() :> Collections.IEnumerator 
    member private this.sl = internalList 
    static member inline (+) (left : TimeSeries<'T>, right : TimeSeries<'T>) = 
     let res = 
      query { 
      for l in left do 
      join r in right on 
       (l.Key = r.Key) 
      select (l.Key, l.Value + r.Value)  
      } 
     new TimeSeries<'T>(res |> dict) 
+3

Oto najprostsza odpowiedź na pytanie, które znam: http://tomasp.net/blog/fsharp-generic-numeric.aspx Skomplikowany temat. –

Odpowiedz

6

Twoje podejście wydaje mi się poprawne. Powód, dla którego twój kod się nie kompiluje, jest taki, że wnioskowanie typu F # wywołuje statyczne ograniczenie (czas kompilacji) dla zmiennej typu 'T, która jest taka sama, jak w definicji typu.

Ogólny parametr definicji typu nie może zostać statycznie rozdzielony (bez typów "kapeluszowych"), ale nic nie stoi na przeszkodzie, aby zdefiniować funkcję lub element, który używa tych ograniczeń podczas kompilacji.

Po prostu zmień zmienną typu 'T na 'U w definicji stałej statycznej (+) i wszystko będzie dobrze.

Nadal będziesz mieć możliwość tworzenia TimeSeries wystąpienie typu, który nie obsługuje (+) (tj: TimeSeries<obj>), ale nie będzie w stanie wykorzystać (+) dla tych przypadkach, w każdym razie jeśli zrobisz to dostaniesz ładny komunikat o błędzie podczas kompilacji.

+0

Świetnie! To działa! Wielkie dzięki! –