对 F# 选项类型执行计算

Performing Calculations on F# option types

我正在尝试编写一些通过返回双选项而不是双选项来处理错误的函数。许多这些函数互相调用,因此将双选项作为输入来输出其他双选项。问题是,我不能用双选项做我可以用双打做的事情——一些简单的事情,比如使用“+”添加它们。

例如,一个函数将两个双精度数相除,returns 一个带有 none 的双精度选项用于除以零错误。然后另一个函数调用第一个函数并向其添加另一个双选项。

请告诉我是否有办法做到这一点,或者我是否完全误解了 F# 选项类型的含义。

这称为提升 - 您可以编写函数以通过两个选项提升另一个函数:

let liftOpt f o1 o2 = 
        match (o1, o2) with
        | (Some(v1), Some(v2)) -> Some(f v1 v2)
        | _ -> None

然后您可以提供要应用的函数,例如:

let inline addOpt o1 o2 = liftOpt (+) o1 o2

最后,我意识到我真正要找的是 Option.get 函数,它只需要一个 'a 选项和 returns 一个 'a。这样,我就可以进行模式匹配,并且 return 我想要的值。

上面提到的

liftA2 将为 'lift' 任何适用于 double 参数的函数提供一种通用方法,以便可以适用于 double option 参数的函数.

但是,对于您的情况,您可能必须自己编写特殊函数来处理您提到的边缘情况

let (<+>) a b =
    match (a, b) with
    | (Some x, Some y) -> Some (x + y)
    | (Some x, None)   -> Some (x)
    | (None, Some x)   -> Some (x)
    | (None, None)     -> None

请注意,liftA2 不会自动将您要将 None 添加到 Some(x) 的情况放入。

divide的liftA2方法也需要一些特殊的处理,但是它的结构一般都是我们自己写的

let (</>) a b =
    match (a, b) with
    | (Some x, Some y) when y <> 0.0d -> Some (x/y)
    | _ -> None

您可以像这样使用这些功能

Some(2.0) <+> Some(3.0) // will give Some(5.0)
Some(1.0) </> Some(0.0) // will give None

此外,严格来说,lift 被定义为 "higher order function" - 接受一个函数和 returns 另一个函数的东西。

所以它看起来像这样:

let liftOpt2 f =
    (function a b ->
        match (a, b) with
        | (Some (a), Some (b)) -> f a b |> Some
        | _ -> None)

在这种情况下,您可能希望考虑 Nullable 而不是 Options,原因有二:

  • 可空值是值类型,而选项是引用类型。如果您有大量这些双精度数的集合,使用 Nullables 会将数字保留在堆栈上而不是将它们放在堆上,从而有可能提高您的性能。
  • Microsoft 提供了一系列内置 Nullable Operators,可让您直接对可空值执行数学运算,就像您尝试对选项执行的操作一样。