4

タイプの記録があります

type tradeLeg = {
    id : int ;
    tradeId : int ;
    legActivity : LegActivityType ;
    actedOn : DateTime ;
    estimates : legComponents ;
    entryType : ShareOrDollarBased ;
    confirmedPrice: DollarsPerShare option;
    actuals : legComponents option ; 


type trade = {
    id : int ;
    securityId : int ;
    ricCode : string ;
    tradeActivity : TradeType ;
    enteredOn : DateTime ;
    closedOn : DateTime ;
    tradeLegs : tradeLeg list  ;
}

明らかに、tradeLegsはトレードの一種です。レッグは決済されているか、決済されていない(または決済されていないが価格が確認されている)可能性があります-したがって、アクティブパターンを定義しました:

let (|LegIsSettled|LegIsConfirmed|LegIsUnsettled|) (l: tradeLeg) = 
        if Helper.exists l.actuals then LegIsSettled
        elif Helper.exists l.confirmedPrice then LegIsConfirmed
        else LegIsUnsettled

次に、取引が決済されているかどうかを判断します(LegIsSettledパターンに一致するすべてのレッグに基づいて:

let (|TradeIsSettled|TradeIsUnsettled|) (t: trade) = 
        if List.exists (
            fun l -> 
                match l with 
                    | LegIsSettled -> false 
                    | _ -> true) t.tradeLegs then TradeIsSettled
        else TradeIsUnsettled

このアクティブパターンの使用にはいくつかの利点がありますが、リストのいずれかのアイテムがアクティパターンに一致する(または一致しない)かどうかを確認するためのより効率的な方法があると思います。それと、List.existを使用します。

質問は2つあります:

  1. これを表現するためのより簡潔な方法はありますか?
  2. 機能/表現を抽象化する方法はありますか

    (fun l -> 
          match l with 
          | LegIsSettled -> false 
          | _ -> true)
    

そのような

let itemMatchesPattern pattern item  =
    match item with
         | pattern -> true
         | _ -> false

そのような私は書くことができました(私はこのデザインパターンを再利用しているので):

let curriedItemMatchesPattern = itemMatchesPattern LegIsSettled
if List.exists curriedItemMatchesPattern t.tradeLegs then TradeIsSettled
        else TradeIsUnsettled

考え?

4

2 に答える 2

7

アクティブなパターンに関する質問に答えるために、より簡単な例を使用します。

let (|Odd|Even|) n = 
  if n % 2 = 0 then Even else Odd

を使用して複数のオプションを持つパターンを宣言すると(|Odd|Even|)、コンパイラはそれをタイプの値を返す関数として理解しますChoice<unit, unit>|Odd|Even|したがって、操作できるアクティブなパターンは、独立して使用できる2つの構成(となど)だけでなく|Odd|、組み合わせ全体|Even|です。

アクティブなパターンをファーストクラスの関数として扱うことは可能ですが、複数のオプションを持つパターンを使用している場合は、それを使って多くのことを行うことはできません。

パターン=(|奇数|偶数|);; valパターン:int->選択

値が指定されたパターンに一致するかどうかをテストする関数を作成できますが、多くの関数が必要になります(Choice型パラメーターの数によってオーバーロードされる型が多数あるため)。

let is1Of2 pattern item = 
  match pattern item with
  | Choice1Of2 _ -> true
  | _ -> false

> is1Of2 (|Odd|Even|) 1  
val it : true

このようなものはあなたの場合にはうまくいくでしょうが、それは完璧にはほど遠いです。

複数の部分的なアクティブパターンを宣言すると、もう少し良い仕事をすることができます(ただし、完全性チェックなど、完全なアクティブパターンのいくつかの優れた側面を失うことはもちろんです)。

let (|Odd|_|) n = 
  if n % 2 = 0 then None else Some()  
let (|Even|_|) n = 
  if n % 2 = 0 then Some() else None

これで、値がパターンに一致するかどうかをチェックする関数を記述できます。

let matches pattern value = 
  match pattern value with
  | Some _ -> true
  | None -> false

> matches (|Odd|_|) 1;;
val it : bool = true
> matches (|Even|_|) 2;;
val it : bool = true

まとめ必要なものを実現するための多少の洗練された方法があるかもしれませんが、アクティブなパターンが標準関数を使用するよりも大きな利点をもたらすかどうかをおそらく検討します。最初に関数を使用してコードを実装し、次にどの構造がアクティブパターンとして役立つかを決定し、後でアクティブパターンを追加することをお勧めします。この場合、通常のコードはそれほど悪くはありません。

type LegResult = LegIsSettled | LegIsConfirmed | LegIsUnsettled

let getLegStatus (l: tradeLeg) =    
    if Helper.exists l.actuals then LegIsSettled   
    elif Helper.exists l.confirmedPrice then LegIsConfirmed   
    else LegIsUnsettled

// Later in the code you would use pattern matching
match getLegStatus trade with
| LegIsSettled -> // ...
| LegIsUnSettled -> // ...

// But you can still use higher-order functions too
trades |> List.exist (fun t -> getLegStatus t = LegIsSettled)

// Which can be rewritten (if you like point-free style):
trades |> List.exist (getLegStatus >> ((=) LegIsSettled))

// Or you can write helper function (which is more readable):
let legStatusIs check trade = getLegStatus trade = check
trades |> List.exist (legStatusIs LegIsSettled)
于 2010-04-19T23:36:20.090 に答える
4

fun x -> match x with |...アクティブなパターンの実際の詳細に関するTomasのポイントに加えて、いつでもに短縮できることに注意してくださいfunction | ...。これにより、数回のキーストロークと、潜在的に無意味な識別子を作成する必要がなくなります。

于 2010-04-19T23:41:56.043 に答える