将期权返回值与期权价值进行比较

时间:2018-10-17 20:52:06

标签: f#

我正在尝试做一些超级简单的事情...

let Average (a : float list) : (float option) =
    let add (x : float) (y : float) = x+y

    match a.Length with
    | 0 -> None
    | 1 -> None
    | _ -> Some((List.fold add 0.0 a)/(float)a.Length)    

let CompareResult func input expected =
         (func input) = expected

这是我的两个功能。 当我做 CompareResult平均[5.8; 6.6; 9.4; 3.5; 4.0](约5.86) 我越来越假了。

任何可能实现此目标的想法都会受到赞赏。 谢谢

1 个答案:

答案 0 :(得分:2)

除了内部表示法的局限性导致的差异外,该问题还可能是由于在浮点算术中计算平均值时精度下降所致。

5.86.ToString "G17"
// val it : string = "5,8600000000000003"
(Seq.average [5.8;6.6;9.4;3.5;4.0]).ToString "G17"
// val it : string = "5,8599999999999994"

考虑使用更合适的数字数据类型:

Seq.average [5.8;6.6;9.4;3.5;4.0] = 5.86
// false
Seq.average [5.8M;6.6M;9.4M;3.5M;4.0M] = 5.86M
// true

要回答实际问题,如何对Option<float>值进行相等测试:通过“提起”浮标,然后对它们进行相等测试。提升是函数编程中monads上的常见操作。

明显简化了,只有两个参数都是Some-cases时,我们才运行定制测试。通过对已区分的工会案例进行模式匹配,可以轻松实现这一点。

let eps = 1e-7  // or whatever is sensible in your domain
let equalityCompareFloatOption x y =
    match x, y with
    | Some x', Some y' -> abs(x' - y') < eps
    | _ -> x = y
// val equalityCompareFloatOption : x:float option -> y:float option -> bool

equalityCompareFloatOption
     (Seq.average[5.8;6.6;9.4;3.5;4.0] |> Some) (Some 5.86)
// val it : bool = true