FsUnit 和检查浮点数的相等性

发布于 2024-09-09 07:46:07 字数 992 浏览 4 评论 0原文

我开始使用 FsUnit 来测试 F# 代码。它使得以 F# 风格表达断言成为可能,例如:

[<Test>]
member this.``Portugal voted for 23 countries in 2001 Eurovision contest``() =
    this.totalVotes 
    |> getYearVotesFromCountry "Portugal" 2001
    |> Seq.length
    |> should equal 23

注意我从 FsUnit 获得的“应该等于 23”。以下是 FsUnit 的定义方式:

let equal x = new EqualConstraint(x)

对于浮点数,事情就没那么简单了。我必须将 EqualConstraint 与 Within 方法一起使用。它自然适合 C#:

Assert.That(result).Is.EqualTo(1).Within(0.05);

当然我希望能够用 F# 编写:

result |> should equal 1 within 0.05

但这行不通。我最终定义了一个新函数:

let almostEqual x = (new EqualConstraint(x)).Within(0.01)

或者如果我想参数化精度,我可以将其指定为第二个参数:

let equalWithin x y = (new EqualConstraint(x)).Within(y)

但它们都不漂亮。我想以更自然的方式为 F# 定义“within”函数,因此它可以与 equal 一起使用。 F# 不支持方法重载,所以看起来我无法以这样的方式定义它,因此“equal”可以单独使用,也可以与“within”一起使用。

有什么想法吗?

I started using FsUnit to test F# code. It makes it possible to express assertion in F# style, for example:

[<Test>]
member this.``Portugal voted for 23 countries in 2001 Eurovision contest``() =
    this.totalVotes 
    |> getYearVotesFromCountry "Portugal" 2001
    |> Seq.length
    |> should equal 23

Note "should equal 23" that I get from FsUnit. Here's how FsUnit defines it:

let equal x = new EqualConstraint(x)

With floating point numbers it's not that simple. I have to use EqualConstraint with Within method. It naturally fits C#:

Assert.That(result).Is.EqualTo(1).Within(0.05);

Of course I'd like to be able to write in F#:

result |> should equal 1 within 0.05

But that does not work. I ended up defining a new function:

let almostEqual x = (new EqualConstraint(x)).Within(0.01)

or if I want to parametrize precision, I can specify it as a second argument:

let equalWithin x y = (new EqualConstraint(x)).Within(y)

But none of them are pretty. I would like to define "within" function in a more natural way for F#, so it can be used together with equal. F# does not support method overloading, so it looks like I can't define it in such a way so "equal" can be used either alone or together with "within".

Any ideas?

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

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

发布评论

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

评论(2

七堇年 2024-09-16 07:46:07

这是一个有趣的问题!我认为您不能以任何方式将 within 0.05 附加到 should equal 的现有定义中。为此,您需要向 should 函数添加参数,但这需要在库中具有固定数量的参数。

在 F# 中优雅地编写此内容的一种方法是创建自定义运算符 +/-。请注意,您仍然需要使用括号,但它看起来非常简洁:

0.9 |> should equal (1.0 +/- 0.5)

运算符只是构造一些需要在 equal 函数中显式处理的特殊类型的值。这是实现:

type Range = Within of float * float
let (+/-) (a:float) b = Within(a, b)

let equal x = 
  match box x with 
  | :? Range as r ->
      let (Within(x, within)) = r
      (new EqualConstraint(x)).Within(within)
  | _ ->
    new EqualConstraint(x)

This is an interesting problem! I don't think that you can append within 0.05 to the existing definition of should equal in any way. To do that you would need to add parameter to the should function, but that needs to have a fixed number of parameters in the library.

One way to write this elegantly in F# would is to create custom operator +/-. Note that you still need to use parentheses, but it looks quite neat:

0.9 |> should equal (1.0 +/- 0.5)

The operator simply constructs some value of a special type that needs to be explicitly handled in the equal function. Here is the implementation:

type Range = Within of float * float
let (+/-) (a:float) b = Within(a, b)

let equal x = 
  match box x with 
  | :? Range as r ->
      let (Within(x, within)) = r
      (new EqualConstraint(x)).Within(within)
  | _ ->
    new EqualConstraint(x)
被你宠の有点坏 2024-09-16 07:46:07

术语说明:F# 确实支持方法重载;它不支持重载let-bound 函数(模块中定义的“自由”函数)。

例如,您可以将其设置为带有点的 should.equal,这样 equal 就是 should 对象上的一个方法,您可以重载该方法。尽管这仍然没有帮助,因为你不能重载柯里化参数。嗯。

好吧,我没有什么可以提供的。就我个人而言,我不喜欢图书馆中的这些类型的语法糖。

Terminology note: F# does support method overloading; it does not support overloading let-bound functions ('free' functions defined in modules).

You could e.g. make it should.equal with a dot, so that equal is a method on the should object, which you could overload. Although that still wouldn't help, since you can't overload curried arguments. Hmmm.

Ok, I don't have much helpful to offer. Personally I don't like these type of syntactic sugars in libraries.

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