F# FsUnit与浮点数的相等性检验

F# FsUnit与浮点数的相等性检验,f#,nunit,fsunit,F#,Nunit,Fsunit,我开始使用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测试F#代码。它可以用F#风格表达断言,例如:

[<Test>]
member this.``Portugal voted for 23 countries in 2001 Eurovision contest``() =
    this.totalVotes 
    |> getYearVotesFromCountry "Portugal" 2001
    |> Seq.length
    |> should equal 23
当然,我希望能够用F#写:

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

let almostEqual x = (new EqualConstraint(x)).Within(0.01)
或者,如果要参数化精度,可以将其指定为第二个参数:

let equalWithin x y = (new EqualConstraint(x)).Within(y)
但他们都不漂亮。我想用一种更自然的方式为F#定义“in”函数,这样它就可以与equal一起使用。F#不支持方法重载,所以看起来我不能这样定义它,“equal”可以单独使用,也可以与“in”一起使用

有什么想法吗?

术语说明:F#支持方法重载;它不支持重载let绑定函数(模块中定义的“free”函数)

例如,可以使用点使其
should.equal
,以便
equal
should
对象上的一个方法,可以重载该方法。尽管这仍然没有帮助,因为你不能过度使用陈词滥调。嗯


好吧,我没有什么有用的。就我个人而言,我不喜欢库中的这种语法糖。

这是一个有趣的问题!我不认为您可以在0.05以内将
附加到
的现有定义中,而
应以任何方式等于
。为此,您需要将参数添加到
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)

你说得对,布莱恩。我的意思是,当然是让约束函数。我喜欢这种糖。我认为这在F#中很重要。哇!真是太需要了!谢谢你的另一个好建议。这个也是基于自定义操作符的。
0.9 |> should equal (1.0 +/- 0.5)
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)