2012-08-15 12 views
7

私は少しこのようになりますC#の方法があります。どのようにして必要な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#では

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#でこれを書く方法?

+2

C#でこれを書くためのクリーンな方法は間違いなくあります。あなたの条件を逆にして、偽を返します。 F#で役立つかどうかは分かりませんが。 –

+0

この質問にはうれしいことがたくさんあります。 –

+0

@Onorio - 私は同意しません。 「面白い」回答がたくさんありますが、私の意見では、ほとんどの回答が複雑さを増しています。ソフトウェアエンジニアとしての目標はそれを減らすことだと思いました。 – Brian

答えて

6

まあは、「いくつかの作業を行う」(おそらく)すでに不可欠であることから、その後、私は

let eval() = 
    let mutable result = false 
    ... // ifs 
     result <- true 
    ... // no more elses 
    result 

が短くかつ合理的であると思います。 (言い換えれば、elseは値のみを返すif表現には必須であり、あなたは絶対に必要な作業をやっているので、else必要がないことifステートメントを使用)Optionモジュールに高階関数を使用して

+0

その簡潔さと他の言語への適用性のために選んだ。 – Asik

4

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 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 

それともさらに明確にするため:任意の可変状態なく、非常にきれいにこの流れを作ることができます

+0

むしろHaskellish(これは私が好きだということです) - これはOptionがモナドであるという事実を利用しています。これは恥ずかしいことですが、F#ではOptionモナドの計算式は実際にはありません。ウェブ上にはいくつかの実装がありますが、コアにあれば素晴らしいことでしょう。 –

6

機能を抽出することを恐れないでください。これは、複雑なロジックを制御する上で重要です。

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 
+0

これは、部品が状態を共有していないことを前提としています。 – Daniel

+2

@Daniel - Stateをパラメータとして渡すことができます。 – ChaosPandion

13
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 
    } 
+3

@ブライアン私はあなたのコメントは、ラインを外れていると思う。人々は、何が何であり、何が可読ではなく、何が何であり、何が良い答えではないかを自分で決めるかもしれません。倫理はさておき、読みやすさは見る人の視点に立っています。異なる背景を持つ人々は、異なるコーディングスタイルを読むのが簡単で困難です。 –

+2

私の意見は、これはひどい答えです。私は、大多数のプログラマが、オリジナルのコード、または基本的なif-thenと単一のローカル可変変数を使って私のようなコードを見たいと思うと思います。このコードは難解な言語機能を使って新しい制御抽象化を導入しています。私は何が、エレガントになるかわからない? 1行を保存しますか?私はそれを得ていない。私はFPコミュニティに複数のサブカルチャーがあると思いますが、私は完全にこの問題に触れていません。 – Brian

+5

@ブライアン:FWIW、私はダイ・ハードFP「サブカルチャー」の一部でもありません。しかし、これはF#の広告であり、1)興味深い/楽しい、2)問題を解決するためのF#の多様なツールキットのデモンストレーション、3)学習に価値があり新しいいくつかのプログラマー(モナド)。それは_もっともなのですか? – Daniel

9

コメントで述べたように、あなたは条件を反転できます。あなたが書くことができるので、これは、C#のコードを簡素化:

if (!conditionA) return false; 
// do some work 

F#は(あなたが返すようにしたい場合、あなたは両方の真と偽の枝を必要とする)が不可欠リターンを持っていませんが、それは実際には、少しもこのコードを簡素化あなたはまだ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 

:あなたが書くことができますので。無制限の複雑なソリューションがありますが、これはおそらく最も簡単なオプションです。より複雑なソリューションについては、F# computation expression that allows using imperative-style returnsを使用できます。これはDanielの計算と似ていますが、もう少し強力です。

1

あなたは、現実世界のケースに応じて、それがより明確にするかもしれない、真理値表のようなものにあなたのコードを作ることができる:

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; 
+0

... condB()とcondC()が不必要に呼び出される可能性は低いですが。 – Kit

+0

このアプローチのパワーを見るには、2番目の一致条件をコメントアウトしてみてください。 VSでは、青い揺れがあり、すべてのケースをカバーしていないという警告が表示されます。 – Kit

+1

私はこれが好きです、パターンマッチングは非常に明確にすることができます。これはまた、それに独特のエルランの感触を持っています:) – 7sharp9

関連する問題