F#中的重载运算符:(/)

时间:2010-05-11 15:40:19

标签: f# operator-overloading inline

我想重写F#中的(/)运算符以获取字符串并保留数字的含义。

/// Combines to path strings
let (/) path1 path2 = Path.Combine(path1,path2)

let x = 3 / 4 // doesn't compile

如果我尝试以下操作,我会收到“警告29扩展成员无法提供操作员重载。请考虑将操作符定义为类型定义的一部分。”

/// Combines to path strings
type System.String with
  static member (/) (path1,path2) = Path.Combine(path1,path2)

有什么想法吗?

此致   forki

4 个答案:

答案 0 :(得分:19)

您无法为现有类型提供重载运算符。一种选择是使用另一个运营商名称(如Natahan建议的那样)。但是,您还可以定义一种新类型来表示F#代码中的路径,并为此类型提供/运算符:

open System    

// Simple type for representing paths
type Path(p) =
  // Returns the path as a string
  member x.Path = p 
  // Combines two paths
  static member ( / )(p1:Path, p2:Path) = 
    Path(IO.Path.Combine(p1.Path, p2.Path))

let n = 4 / 2
let p = Path("C:\\") / Path("Temp")

这有一个重要的好处 - 通过使类型更明确,您可以为类型检查器提供更多可用于验证代码的信息。如果使用字符串表示路径,则可以轻松地将路径与其他字符串(例如名称)混淆。如果您定义了Path类型,则类型检查器将阻止您犯这个错误。

此外,编译器不允许(简单地)错误地组合路径(如果将路径表示为字符串,则很容易发生),因为p + p未定义(只能​​使用/ },正确使用Path.Combine)。

答案 1 :(得分:9)

其实你可以。

试试这个:

open System.IO

type DivExtension = DivExtension with
    static member inline (=>) (x             , DivExtension) = fun y -> x / y
    static member        (=>) (x             , DivExtension) = fun y -> Path.Combine(x, y)
    static member        (=>) (x:DivExtension, DivExtension) = fun DivExtension -> x

let inline (/) x y = (x => DivExtension) y

答案 2 :(得分:8)

我认为没有一种直截了当的方法可以做到这一点。 F#中的运算符重载不考虑扩展成员,并且没有一种使用成员约束以半通用方式重新定义操作的好方法。

可以将可能起作用的东西放在一起,但这很难看:

type DivisionOperations =
  static member Divide(x:int, y:int) = x / y
  static member Divide(path1, path2) = Path.Combine(path1, path2)

let inline div< ^t, ^a, ^b, ^c when (^t or ^a) : (static member Divide : ^a * ^b -> ^c)> a b = ((^t or ^a) : (static member Divide : ^a * ^b -> ^c) (a, b))

let inline (/) x y = div<DivisionOperations, _, _, _> x y

答案 3 :(得分:6)

根据the overloading documentation的读数,我不认为在F#中这是可能的。

我建议您创建自己的看起来像 /的功能,但不是。类似的东西:

let (</>) path1 path2 = Path.Combine (path1,path2)

从长远来看,这可能不那么烦人,因为它不会弄乱人类读者正在运行的隐式类型推断 - /意味着结果是一个浮点,并记住它有时是一个字符串是负担*。但是在读者第一次看到</>之后,很容易记住它与嵌入在中间的符号有关。

*我认为+字符串看起来正常的唯一原因是过度曝光。在使用Haskell或Caml很长一段时间后,切换到另一种语言后的前几分钟使"foo" + "bar"看起来很糟糕。