编写函数的最佳方法是什么,以便它们可以无缝地处理:
我特别需要编写函数,例如计算时间序列的平均值/方差/随机变换,我想只写这些函数的1个版本。
答案 0 :(得分:13)
正如评论中所述,关键问题是您希望在数据类型上写什么样的操作。有可能为基本的数值运算执行此操作,但如果您需要一些更复杂的计算,那么编写两个单独的函数可能会更容易。
无论如何,如果要使用基本数值运算,则需要为时间戳类型定义标准数字运算符。我描述了this in a recent article。以下实现+
,除以整数和零:
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 }
+
运算符有点可疑,因为你最终会得到一些非常大的日期(并且最后使用TimeSpan
可能更有意义)。但是,一旦定义了运算符,您就可以使用Seq.average
:
[ { Time = DateTime.Now
Value = 3.0 }
{ Time = DateTime.Now.AddDays(2.0)
Value = 10.0 } ]
|> Seq.average
Seq.average
函数适用于这两种类型,因为它是使用静态成员约束编写的(这意味着它适用于任何具有必要成员的类型)。编写这样的函数比编写普通函数更困难,所以默认情况下我可能不会使用这种函数。无论如何,这是一个introduction with more examples和SO answer shows more useful tricks。
编辑 - 正如Jon Harrop指出的那样,这是一种非常复杂的方法,它只会给你带来有限的好处。如果您只需要使用值,那么转换为值序列是一种更好的方法。如果您需要更复杂的计算,那么我认为编写泛型函数并不值得。为float和timestamped值编写两个单独的函数可能会更容易。
答案 1 :(得分:9)
只需将带时间戳的seq转换为float seq,如下所示:
xs
|> Seq.map (fun x -> x.value)