As indicated in the commentary, the key question is which operations you want to write by data type. This may be possible for basic numerical operations, but if you need more complex calculations, it will probably be easier to write two separate functions.
In any case, if you want to use basic numeric operations, you need to define standard numeric operators for your time stamp. I described this in a recent article . The following implements + , division by integer and zero:
open System type TimedFloat = { Time : DateTime Value : float } static member (+) (tf1, tf2) = { Time = DateTime(tf1.Time.Ticks + tf2.Time.Ticks) Value = tf1.Value + tf2.Value } static member Zero = { Time = DateTime.MinValue Value = 0.0 } static member DivideByInt(tf, n) = { Time = DateTime(tf.Time.Ticks / int64 n) Value = tf.Value / float n }
The + operator is a little suspicious because you will have a very big date (and maybe using TimeSpan from the latter makes more sense). However, once you define the operators, you can, for example, use Seq.average :
[ { Time = DateTime.Now Value = 3.0 } { Time = DateTime.Now.AddDays(2.0) Value = 10.0 } ] |> Seq.average
The Seq.average function works on both types because it is written using static member constraints (which means that it works on any type that has the necessary elements). Writing such functions is more complicated than writing a normal function, so I probably would not use this default style. Anyway, this is an introduction with a lot of examples , and this SO answer shows more useful tricks .
EDIT - As John Harrop points out, this is a rather complicated approach, and it gives you only limited benefits. If you just need to work with values, then itβs better to move on to a sequence of values. If you need more complex calculations, then I don't think it's worth writing a generic function. Perhaps two separate functions for floating point and timestamped values ββwill be written.