如何在 F# 的度量单位上定义扩展成员?

10

撇开我们是否应该在无单位概念(例如角度)中使用度量单位,假设我已经在F#中定义了degreeradian单位。

type [<Measure>] degree =
    static member ToRadians (d:float<degree>) : float<radian> = d * (Math.PI * 1.<radian>) / 180.0<degree>
and [<Measure>] radian =
    static member ToDegrees (r:float<radian>) : float<degree> = r * 180.0<degree> / (Math.PI * 1.<radian>)

我可以相对容易地使用它们,例如:

4.0<degree> |> degree.ToRadians

看起来扩展成员可能会更加方便。那么我只需要这样说

let d = 4.0<degree>
let r = d.ToRadians()

但是我无法以显而易见的方式定义扩展成员

type float<degree> with
    member degrees.ToRadians() = degree.ToRadians(degrees)

......这导致了以下错误

error FS0010: Unexpected identifier in type name. Expected infix operator, quote symbol or other token.

F#是否有对单位尺度上的扩展成员进行语法技巧的支持,还是该特性受支持?


我猜测它不被支持。我尝试的所有方法都出现了错误:“度量声明只能有静态成员”。 - Daniel
1
问题在于度量类型信息在编译后被删除,因此在运行时一切都只是一个“float”,因此调用实例方法就没有意义了。 - John Palmer
1
在编译期间,扩展成员会被静态解析。 - Sebastian Good
@Sebastion Good - 没错,一旦类型检查完成,额外的类型信息就会被移除,你的代码只是编译成标准的floats操作。 - John Palmer
1个回答

6

F#扩展成员与C#扩展成员不同,因为您无法定义构建的泛型类型的扩展。例如,您可以在seq<'t>上定义扩展,但不能在seq<int>上定义扩展。换句话说,扩展成员实际上像类型的成员一样,而不是静态方法。这也适用于度量类型,因此您无法在float<degree>上定义扩展,但可以在float<[<Measure>]'u>上定义扩展:

type float<[<Measure>]'u> with
    member f.Squared() = f * f

[<Measure>]
type m

let area = 2.0<m>.Squared()

然而,我不认为这会对你的情况有所帮助...

这很有道理。定义这些扩展方法除了语法之外,没有任何实际好处,而且还有很多其他不错的选择。 - Sebastian Good

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接