如何根据 F# 中许多昂贵计算的 or-else 计算结果
How to calculate a result based on or-else of many expensive computations in 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# 中编写此类代码的正确方法是什么?
我认为将 LastExpensiveComputationThatNeverFails
设为一个本地函数,只要需要结果就可以调用它。
但是,也可以将操作更改为 return Option<_>
并使用内置的组合函数。
let MyMethod () =
SomeExpensiveComputation1 ()
|> Option.orElseWith
( fun () ->
SomeExpensiveComputation2 ()
|> Option.bind (fun _ -> SomeExpensiveComputationOn2_1 () |> Option.orElseWith SomeExpensiveComputationOn2_2)
)
|> Option.orElseWith LastExpensiveComputationThatNeverFails
Option.orElseWith LastExpensiveComputationThatNeverFails
仅当先前的结果为 None
时才执行,失败时将执行此操作。
假设我有以下伪 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# 中编写此类代码的正确方法是什么?
我认为将 LastExpensiveComputationThatNeverFails
设为一个本地函数,只要需要结果就可以调用它。
但是,也可以将操作更改为 return Option<_>
并使用内置的组合函数。
let MyMethod () =
SomeExpensiveComputation1 ()
|> Option.orElseWith
( fun () ->
SomeExpensiveComputation2 ()
|> Option.bind (fun _ -> SomeExpensiveComputationOn2_1 () |> Option.orElseWith SomeExpensiveComputationOn2_2)
)
|> Option.orElseWith LastExpensiveComputationThatNeverFails
Option.orElseWith LastExpensiveComputationThatNeverFails
仅当先前的结果为 None
时才执行,失败时将执行此操作。