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

发布于 2024-09-01 07:42:13 字数 416 浏览 6 评论 0原文

我想在 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)

有什么想法吗?

问候, 福尔基

I would like to overload the (/) operator in F# for strings and preserve the meaning for numbers.

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

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

If I try the following I get "Warning 29 Extension members cannot provide operator overloads. Consider defining the operator as part of the type definition instead."

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

Any ideas?

Regards,
forki

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

笑忘罢 2024-09-08 07:42:13

您无法为现有类型提供重载运算符。一种选择是使用另一个运算符名称(如 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)。

You cannot provide overloaded operators for existing types. One option is to use another operator name (as Natahan suggests). However, you can also define a new type to represent paths in your F# code and provide the / operator for this type:

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")

This has one important benefit - by making the types more explicit, you give the type checker more information that it can use to verify your code. If you use strings to represent paths, then you can easily confuse path with some other string (e.g. name). If you define your Path type, the type-checker will prevent you from making this mistake.

Moreover, the compiler won't allow you to (simply) combine paths incorrectly (which can easily happen if you represent paths as strings), because p + p is not defined (you can use only /, which correctly uses Path.Combine).

我爱人 2024-09-08 07:42:13

我认为没有直接的方法可以做到这一点。 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

I don't think that there is a straightforward way to do that. Extension members aren't taken into consideration for operator overloading in F#, and there isn't a good way to redefine the operation in a semi-generic way using member constraints.

It is possible to hack something together that will work, but it's very ugly:

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
霞映澄塘 2024-09-08 07:42:13

其实你可以。

试试这个:

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

Actually you can.

Try this:

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
挽清梦 2024-09-08 07:42:13

根据对重载文档的阅读,我认为这在 F# 中是不可能的/a>.

相反,我建议您创建自己的函数,它看起来像 / 但事实并非如此。类似于:

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

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

*我认为 + 字符串看起来不错的唯一原因是过度曝光。长期使用 Haskell 或 Caml 后,切换到另一种语言后的前几分钟会让 "foo" + "bar" 看起来非常糟糕。

I do not think this is possible in F#, based on a reading of the overloading documentation.

I would instead suggest that you create your own function which looks like / but isn't. Something like:

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

This is likely to be less annoying in the long run because it doesn't mess with the implicit type inference that the human reader is running--/ means that the result is a floating point, and remembering that it's sometimes a string is a burden*. But after the first time the reader sees </>, it's easy to remember that it does something related to the symbol embedded in the middle.

*I think the only reason + for strings looks OK is over-exposure. After using Haskell or Caml for a long time, the first few minutes after switching to another language makes "foo" + "bar" look jarringly bad.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文