在F#中,你如何处理(float seq)和{ts:DateTime; value:float}以通用方式?

时间:2012-10-24 09:15:16

标签: coding-style f#

编写函数的最佳方法是什么,以便它们可以无缝地处理:

  • a float seq
  • 类型的时间戳系列{ts:DateTime; value:float} seq,其值在float中,名为value

我特别需要编写函数,例如计算时间序列的平均值/方差/随机变换,我想只写这些函数的1个版本。

2 个答案:

答案 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 examplesSO answer shows more useful tricks

编辑 - 正如Jon Harrop指出的那样,这是一种非常复杂的方法,它只会给你带来有限的好处。如果您只需要使用,那么转换为值序列是一种更好的方法。如果您需要更复杂的计算,那么我认为编写泛型函数并不值得。为float和timestamped值编写两个单独的函数可能会更容易。

答案 1 :(得分:9)

只需将带时间戳的seq转换为float seq,如下所示:

xs
|> Seq.map (fun x -> x.value)