是否可以将现有类型扩展为与Seq.sum等一起使用? [英] Can existing types be extended to work with Seq.sum, etc?

查看:47
本文介绍了是否可以将现有类型扩展为与Seq.sum等一起使用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近开始与许多TimeSpans合作,并且需要获得总和&平均.
但是,TimeSpan既没有定义运算符get_Zero也没有定义DivideByInt,因此Seq.sum和Seq.average不能直接用于此类型.以下内容无法编译:

Been working with a lot of TimeSpans recently, and have a need to get sums & averages.
However, TimeSpan defines neither operator get_Zero nor DivideByInt, so Seq.sum and Seq.average can't be used directly with this type. The following fails to compile:

open System
type System.TimeSpan
    with
        static member Zero with get() = TimeSpan()
        static member (/) (n:DateTime, d:int) = DateTime( n.Ticks / (int64) d )

let ts = [ TimeSpan(10L); TimeSpan(99L) ]
let sum = ts |> Seq.sum
let avg = ts |> Seq.average

  • 错误:"TimeSpan"类型不支持任何名为"get_Zero"的运算符
  • 错误:类型'TimeSpan'不支持任何名为'DivideByInt'的运算符
  • 警告:扩展成员无法提供操作员重载.考虑将运算符定义为类型定义的一部分.
  • 是否有一些F#魔术可以在现有类型上定义这些运算符?

    Is there some F# magic that can define these operators on an existing type?

    我知道以下方法会起作用(并且应该更有效地启动),但是我仍然对以上内容感到好奇,因此可以将其添加到我的工具箱中以用于其他类型.

    I know the following will work (and should be more efficient to boot), but I'm still curious about the above so I can add it to my toolbox for use with other types.

    let sum = TimeSpan( ts |> Seq.sumBy (fun t -> t.Ticks) )
    let avg = TimeSpan( let len = ts |> Seq.length in sum.Ticks / int64 len )
    

    推荐答案

    据我所知,静态成员约束(由 Seq.sum 之类的函数使用)不能发现成员这些都是通过类型扩展(基本上是扩展方法)添加的,所以我认为没有直接的方法可以做到这一点.

    As far as I know, static member constraints (that are used by functions like Seq.sum) are not able to discover members that are added by type extensions (essentially, extension methods), so I don't think there is a direct way of doing this.

    我能想到的最好的选择是围绕 System.TimeSpan 结构创建一个简单的包装.然后,您可以定义所有必需的成员.代码如下:

    The best option I can think of is to creat a simple wrapper around the System.TimeSpan struct. Then you can define all the required members. The code would look like this:

    [<Struct>]
    type TimeSpan(ts:System.TimeSpan) =
      member x.TimeSpan = ts
      new(ticks:int64) = TimeSpan(System.TimeSpan(ticks))
      static member Zero = TimeSpan(System.TimeSpan.Zero)
      static member (+) (a:TimeSpan, b:TimeSpan) = 
        TimeSpan(a.TimeSpan + b.TimeSpan)
      static member DivideByInt (n:TimeSpan, d:int) = 
        TimeSpan(n.TimeSpan.Ticks / (int64 d)) 
    
    let ts = [ TimeSpan(10L); TimeSpan(99L) ] 
    let sum = ts |> Seq.sum 
    let avg = ts |> Seq.average 
    

    我称类型为 TimeSpan ,因此它隐藏了标准的 System.TimeSpan 类型.但是,当您需要访问基础系统类型时,仍然需要编写 ts.TimeSpan ,因此这并不尽如人意.

    I called the type TimeSpan, so it hides the standard System.TimeSpan type. However, you still need to write ts.TimeSpan when you need to access the underlying system type, so this isn't as nice as it could be.

    这篇关于是否可以将现有类型扩展为与Seq.sum等一起使用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆