假设我具有以下伪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#编写此类代码的正确方法是什么?
答案 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
且失败时才执行。