2016-04-16 6 views
4

F#でこのコードを書くためのより良い方法があるかどうか私は思ったんだけど:F#パターンマッチ可変長最初の単語で区切られた単語のコマンド

let run (command : string) = 
    let words = command.Split [|','|] 
    match words.[0] with 
     | a when a .eignore "optionA" -> optionA words.[1] words.[2] words.[3] 
     | a when a .eignore "optionB" -> optionB words.[1] words.[2] words.[3] words.[4] words.[5] 
     | a when a .eignore "optionC" -> optionC words.[1] words.[2] words.[3] words.[4] 
     | a when a .eignore "optionD" -> optionD words.[1] words.[2] words.[3] words.[4] 
     | a when a .eignore "optionE" -> optionE words.[1] words.[2] words.[3] 
     | a when a .eignore "optionF" -> optionF words.[1] words.[2] 
     | a when a .eignore "optionG" -> optionG words.[1] words.[2] words.[3] words.[4] 
     | _ ->() 

私はF#に新しいですし、私はこのことを感じますステートメントはかなり反復的であり、公正なビットをより良く行うことができるかもしれませんが、どこから始めるのかは本当にわかりません。

基本的にはそれが何をするかでは、コマンドがカンマで区切られた文字列の最初の部分であることで、コマンドを実行し、残りの入力であること: 例入力:

optionA,1,2,A,Test

また.eignoreだけです文字列が大文字小文字を無視して等しいかどうかをチェックするカスタム関数。

+1

'optionA'、' optionB'などとは何ですか?入力と予想される出力を含む[最小、完全、および検証可能な例](http://stackoverflow.com/help/mcve)を提供してください。 –

+0

入力例は 'optionA、1,2、A、Test'の上にリストされています。' optionA' 'optionB'は単なるメソッドです。出力する必要はありません。関数は何かを実行します。 –

+1

出力が必要ない場合は、関数を次のようにリファクタリングすることができます: 'let run x =()'。 –

答えて

4

複合パターンマッチングを使用してこれを行うことができます。あなたが標準cons patternにこのEqIgnoreCaseパターンを作成することができ

let (|EqIgnoreCase|_|) x y = 
    if String.Equals(x, y, StringComparison.OrdinalIgnoreCase) 
    then Some() 
    else None 

:あなたは、大文字と小文字を区別しない文字列比較のためにactive patternをする必要があります

let run (command : string) = 
    let words = command.Split [|','|] |> Array.toList 
    match words with 
    | EqIgnoreCase "optionA" :: u :: v :: x :: _   -> optionA u v x 
    | EqIgnoreCase "optionB" :: u :: v :: x :: y :: z :: _ -> optionB u v x y z 
    | EqIgnoreCase "optionC" :: u :: v :: x :: y :: _  -> optionC u v x y 
    | EqIgnoreCase "optionD" :: u :: v :: x :: y :: _  -> optionD u v x y 
    | EqIgnoreCase "optionE" :: u :: v :: x :: _   -> optionE u v x 
    | EqIgnoreCase "optionF" :: u :: v :: _    -> optionF u v 
    | EqIgnoreCase "optionG" :: u :: v :: x :: y :: _  -> optionG u v x y 
    | _ ->() 

それは短所パターンの代わりに、配列を使用するのが最も簡単ですこれは、ワイルドカードパターン(_)を使用してリストの末尾を簡単に無視できるためです。引数のリストが短すぎるため、最後の行には何のコンソール出力を持っていないことを

> run "optionA,1,2,A,Test";; 
optionA 1 2 A 
val it : unit =() 

> run "optionB,1,2,A,Test,Foo";; 
optionB 1 2 A Test Foo 
val it : unit =() 

> run "OPTIONA,1,2,A,Test";; 
optionA 1 2 A 
val it : unit =() 

> run "OPTIONA,1,2,A";; 
optionA 1 2 A 
val it : unit =() 

> run "OPTIONA,1,2";; 
val it : unit =() 

は注意:ここで

は、いくつかの関数呼び出しです。

+0

これはうまくいきました。以前はアクティブなパターンマッチングについて知らなかった。ありがとう! :) –

1

ほとんどの繰り返しのようですが、あなたの関数に引数を渡すことになります。明白な解決策は、それらを文字列配列を受け入れるようにすることです:

let cmdName = function {name = n; action = _} -> n 
let cmdAction = function {name = _; action = a} -> a 
:もちろん

type Command = { name : string; action : string array -> unit } 

、あなたは次に、のは、新しいタイプのためのいくつかのアクセサを作ってみようなど、引数の数のようないくつかのフィールドの検証を追加することができます

そして、大文字と小文字を区別しない文字列比較を実装:

0123:今、私たちは主な機能を実装する準備が整いました

let icmp a b = String.Compare(a, b, true) = 0 

type Class() as __ = 
    member __.optionC(args : string array) = printfn "optionC!" 
    static member optionD(args : string array) = printfn "optionD" 

let run (command : string) = 
    let words = command.Split [|','|] 
    [ { name = "optionA"; action = fun args -> printfn "%A" args } 
    { name = "optionB"; action = fun _ -> printfn "optionB!" } 
    { name = "optionC"; action = fun args -> (new Class()).optionC(args) } 
    { name = "optionD"; action = Class.optionD } ] 
    |> List.tryFind(cmdName >> (icmp words.[0]))     // [1] 
    |> Option.iter(cmdAction >> ((|>) words.[1..words.Length - 1]) // [2]) 

[1]コマンドリストを作成し、最初の引数の名前でコマンドを検索します。

[2]最後に、すべての引数をアクションに渡します(optionA関数ファミリはそれを効果的に実行します)。

Option.iterは、必要なコマンドが見つかった場合にのみペイロードを実行することに注意してください。

+0

私はこれが好きです。私はこの段階でどのようにそれを完全に理解しようとしています。ハハ。 –

+0

アクションでは、アクションごとにカスタムメソッドを持つことが可能ですか?例: '{name =" optionA "; action = custom_method} ' argsが直接メソッドに渡されるようにします。 –

+0

私の更新を参照してください。また、メソッド(OOスタイル)に関数を優先しようとします。すべての関数は同じシグニチャを持つ必要があります(ただし、アクション型の識別されたユニオンとは異なる可能性があります)。 – yuyoyuppe

関連する問題