我想重写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
答案 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"
看起来很糟糕。