3

我开始使用 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 的定义:

让等于 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# 定义“内部”函数,因此它可以与 equal 一起使用。F# 不支持方法重载,所以看起来我无法以这种方式定义它,因此“equal”可以单独使用,也可以与“within”一起使用。

有任何想法吗?

4

2 回答 2

12

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

在 F# 中优雅地编写此代码的一种方法是创建自定义 operator +/-。请注意,您仍然需要使用括号,但它看起来很整洁:

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)
于 2010-07-08T16:27:08.530 回答
0

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

例如,您可以should.equal用一个点来制作它,所以这equal是对象上的一个方法should,您可以重载它。尽管这仍然无济于事,因为您不能重载咖喱参数。嗯。

好吧,我没有太多帮助。就我个人而言,我不喜欢图书馆中这些类型的语法糖。

于 2010-07-08T16:20:31.040 回答