如何基于F#中许多昂贵的计算的其他结果来计算结果

时间:2019-02-26 06:20:20

标签: f# c#-to-f#

假设我具有以下伪C#代码:

TResult MyMethod()
{
    var firstTry = SomeExpensiveComputation1();
    if (firstTry.IsSuccessful) return firstTry;

    var secondTry = SomeExpensiveComputation2();
    if (secondTry.IsPartiallySuccessful)
    {
        var subTry1 = SomeExpensiveComputationOn2_1(secondTry);
        if (subTry1.IsSuccessful) return subTry1;

        var subTry1 = SomeExpensiveComputationOn2_2(secondTry);
        if (subTry1.IsSuccessful) return subTry1;
    }

    return LastExpensiveComputationThatNeverFails();
}

如果我要在F#中执行此操作,它将看起来像这样:

let MyMethod () =
    let firstTry = SomeExpensiveComputation1 ()
    if firstTry.IsSuccessful then firstTry else
        let secondTry = SomeExpensiveComputation2 ()
        if secondTry.IsSuccessful then
            let subTry1 = SomeExpensiveComputationOn2_1 ()
            if subTry1.IsSuccessful then subTry1 else
                let subTry2 = SomeExpensiveComputationOn2_2 ()
                if subTry2.IsSuccessful then subTry2 else LastExpensiveComputationThatNeverFails ()
        else
            LastExpensiveComputationThatNeverFails()

如您在上面看到的,我不得不重复LastExpensiveComputationThatNeverFails两次。这不必一定是方法调用,它可以是许多行内联计算(例如,尝试从缓存中获取一些值,如果不存在,请计算它。)一个人可以将代码重构为另一个函数,但是我仍然不喜欢相同的代码(即使只是一行)必须被写入两次(或更多次),因为这会导致重复和混乱的维护。用F#编写此类代码的正确方法是什么?

1 个答案:

答案 0 :(得分:3)

我认为最好将LastExpensiveComputationThatNeverFails设为在需要结果时调用的局部函数。

但是,也可以更改操作以返回Option<_>并使用内置的组合器函数。

let MyMethod () =
  SomeExpensiveComputation1 ()
  |> Option.orElseWith
    ( fun () -> 
        SomeExpensiveComputation2 ()
        |> Option.bind (fun _ -> SomeExpensiveComputationOn2_1 () |> Option.orElseWith SomeExpensiveComputationOn2_2)
    )
  |> Option.orElseWith LastExpensiveComputationThatNeverFails

Option.orElseWith LastExpensiveComputationThatNeverFails仅在先前的结果为None且失败时才执行。