Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

f# Statically resolved types in type members

I want to implement IEnumerable<KeyValuePair<DateTime, 'T>> in my own class and add math operators to that class so that the operators could work like inline function on any numeric types of 'T - automatically add constraints.

I just cannot make the following piece of code work. It doesn't work neither with nor without 'inline' keyword at the member declaration.

Also, if I define a function

let inline add l r = l + r 

before the type and use it instead of addition l.Value + r.Value, it also doesn't work.

Could someone please show me what I am doing wrong?

Probably the whole approach is wrong and there is a way to achieve the same goal the other way?

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)
like image 397
V.B. Avatar asked Dec 24 '12 18:12

V.B.


1 Answers

Your approach seems correct to me. The reason why your code doesn't compile is because F# type inference is inferring a static constraint (compile-time) for the type variable 'T which is the same used for the type definition.

A generic parameter of a type definition can't be statically resolved (no "hat" types) but nothing stops you from defining a function or a member which uses these compile-time constraints.

Just change your type variable 'T to 'U in the static member (+) definition and it will be fine.

Still you'll be allowed to create a TimeSeries instance of a type which does not support (+) (ie: TimeSeries<obj>) but you will not be able to use (+) for those instances, anyway if you do it you'll get a nice error message at compile-time.

like image 69
Gus Avatar answered Nov 08 '22 17:11

Gus