nicolas
nicolas

Reputation: 9805

Apply Seq module operations to a subtype while keeping original type in f#

I want to specialise the list type to represent a time serie. This will allow for some additional methods and better readibility.

I would like to reuse all the functions written in the Seq module, while keeping the original underlying type.

module Analytics =
   open System

   type TimeSerie<'T> () =
      inherit ResizeArray<DateTime*'T> ()


module TimeSerie =
   open Analytics
   let filter f (ts:TimeSerie<'T>) = (Seq.filter f (ts)) |> ResizeArray.ofSeq :?> TimeSerie<'T> 
   .... same for map, etc..

Is there any alternate way to do this that could cut code ?

Upvotes: 1

Views: 142

Answers (2)

pad
pad

Reputation: 41290

In short, no.

There is no easy way to do it. That's one reason why List, Array and Seq modules have their own implementations of those high-order functions.

In your example, I suggest to use ResizeArray module from F# PowerPack, where you have all high-order functions ready to use. Specialization to ResizeArray<DateTime*'T> could be done by wrapping it in a single-case discriminated unions.

Upvotes: 2

kvb
kvb

Reputation: 55184

In general, there is no way to do what you want since there is no standard way to build arbitrary subtypes of 't seq in F# or .NET. The only semi-mainstream programming language that I'm aware of that does something like what you're looking for is Scala, and the Scala collections library is notoriously intricate.

To illustrate one of the problems with defining a more "generic" Seq.filter function, consider the following type definition:

type Singleton<'t>(t:'t) =
    interface seq<'t> with
        member __.GetEnumerator() : System.Collections.IEnumerator = 
            ([t] :> System.Collections.IEnumerable).GetEnumerator()
        member __.GetEnumerator() : System.Collections.Generic.IEnumerator<'t> = 
            ([t] :> seq<_>).GetEnumerator()

Now all instances of this class have exactly one element, but filtering will either result in a sequence with zero or one elements. Clearly, this means that the static type of

Singleton(1)
|> Seq.filter (fun x -> x > 5)

must be something other than Singleton<int>.

Upvotes: 1

Related Questions