[英]How can I refactor out the required else clause?
我有一個看起來像這樣的C#方法:
bool Eval() {
// do some work
if (conditionA) {
// do some work
if (conditionB) {
// do some work
if (conditionC) {
// do some work
return true;
}
}
}
return false;
}
在F#中,由於強制執行else分支,最終看起來很難看:
let eval() =
// do some work
if conditionA then
// do some work
if conditionB then
// do some work
if conditionC then
// do some work
true
else
false
else
false
else
false
用F#編寫此代碼的更干凈的方法是什么?
module Condition =
type ConditionBuilder() =
member x.Bind(v, f) = if v then f() else false
member x.Return(v) = v
let condition = ConditionBuilder()
open Condition
let eval() =
condition {
// do some work
do! conditionA
// do some work
do! conditionB
// do some work
do! conditionC
return true
}
如評論中所述,您可以逆轉條件。 這可以簡化C#代碼,因為您可以編寫:
if (!conditionA) return false;
// do some work
盡管F#沒有強制性的返回值(如果要返回,則需要true和false分支),但實際上它也簡化了這段代碼,因為您可以編寫:
let eval() =
// do some work
if not conditionA then false else
// do some work
if not conditionB then false else
// do some work
if not conditionC then false else
// do some work
true
您仍然必須多次編寫false
,但至少不必使代碼縮進太多。 無限數量的復雜解決方案,但這可能是最簡單的選擇。 對於更復雜的解決方案,您可以使用允許使用命令式return的F#計算表達式 。 這類似於Daniel的計算,但功能更強大。
好吧,既然“做一些工作”已經是必須的(大概),那么我認為
let eval() =
let mutable result = false
... // ifs
result <- true
... // no more elses
result
較短且合理。 (換句話說, else
僅對於返回值的if
表達式是必需的;由於您正在執行命令性工作,請使用不需要else
if
語句。)
請不要害怕提取函數。 這是控制復雜邏輯的關鍵。
let rec partA () =
// do some work
let aValue = makeA ()
if conditionA
then partB aValue
else false
and partB aValue =
// do some work
let bValue = makeB aValue
if conditionB
then partC bValue
else false
and partC bValue =
// do some work
conditionC
在Option
模塊中使用高階函數可以使此流程非常干凈,而不會發生任何可變狀態:
let Eval () =
// do some work
if not conditionA then None else
// do some work
Some state
|> Option.bind (fun state ->
if not conditionB then None else
// do some work
Some state')
|> Option.bind (fun state ->
if not conditionC then None else
// do some work
Some true)
|> defaultArg <| false
或為了進一步清楚起見,使用命名函數而不是lambda:
let Eval () =
let a () =
if not conditionA then None else
// do some work
Some state
let b state =
if not conditionB then None else
// do some work
Some state'
let c state =
if not conditionC then None else
// do some work
Some true
// do some work
a () |> Option.bind b |> Option.bind c |> defaultArg <| false
您可以將代碼放入一種真值表,這取決於您的實際情況,可能使其更加明確:
let condA() = true
let condB() = false
let condC() = true
let doThingA() = Console.WriteLine("Did work A")
let doThingB() = Console.WriteLine("Did work B")
let doThingC() = Console.WriteLine("Did work C")
let Eval() : bool =
match condA(), condB(), condC() with
| true, false, _ -> doThingA(); false;
| true, true, false -> doThingA(); doThingB(); false;
| true, true, true -> doThingA(); doThingB(); doThingC(); true;
| false, _, _ -> false;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.