2015-12-06 4 views
6

F#新規の質問。 (|タイプ2 |タイプ3タイプ1)F#ジェネリックファンクションフィルタリングされた組合のフィルタリスト

type Type1 = { name:string; id: int; } 
type Type2 = { x: float; y: float;} 
type Type3 = { x: float; naam:string} 
type Union1 = 
    | T1 of Type1 
    | T2 of Type2 
    | T3 of Type3 
let lst1 = [ T1 {name="nnn"; id=3}; T2 {x=1.1; y=1.3}; T1 {name="naam1"; id=39}; T3{x=0.0; naam="xx"}]; 

//To filter out items of Type1, i do: 
let fltT1 (l:list<Union1>) :list<Type1> = 
    let rec loop (l:list<Union1>) (acc:list<Type1>) = 
     match l with 
     | h::t -> match h with 
        // this is now specific per type 
        | T1{name=n;id=i} -> loop t ({name=n;id=i}::acc) 
        | _ -> loop t acc 
     | [] -> acc 
    loop l [] |> List.rev 

がどのように私は、一般的なような関数が呼び出し 必要な出力タイプに指定することができます:私のような差別組合のリストを持っている ?

+0

問題は解決しましたか? –

答えて

8

私のアプローチはおそらくList.chooseまたはSeq.chooseを使用するだけです。それはfilter/mapよりも利点があります。パターンマッチを1回だけ実行する必要があり、それはfoldよりはるかに簡潔です。

lst1 
|> List.choose 
    (function 
    |T1 res -> Some res 
    |_ > None) 

chooseマップと組み合わせフィルタのようなものであり、その結果はSomeたすべての要素に対してf(x)を返し、それがNoneたすべての要素を無視します。この例では、戻り値の型はType1 listです。特定の労働組合のケースに基づいて機能をParametrising


が、これは特定の労働組合の例は、それ自体のタイプではないので、彼らは単に労働組合タイプのコンストラクタあるある、ことはできません。あなたの例のT1はタイプではなく、Union1です。つまり、ある時点で、それを分解するために明示的なパターンマッチが必要です。 (これはすべての関数型言語に当てはまるわけではないことに注意してください。スカラの結合ケースは継承でモデル化されていますが、F#はHaskell、Ocamlなどの手法を採用しています)。

lst1 |> List.choose (tryAssumeT1) 
:あなたは、この構文を使用することができます

static member tryAssumeT1 = function 
    |T1 t1 -> Some t1 
    | _ -> None 

:フョードルSoikinが述べたように

、あなたは静的メンバまたはご希望の場合の例として、各ケースに対してチェックする機能を書くことができます

+0

ありがとう、それは素敵で短いです。 しかし、Type1、Type2、Type3の項目を除外するために別の式(関数)を記述する必要があるようです。 必要なタイプのパラメータ化された関数を作成することは可能ですか? – RobF

+0

'static1メンバ' t1 = function T1 t - > Some tのように、 'Union1'型のアクセサ関数を提供することでうまくエンコードできます。 List.choose Union1.t1'のように 'List.choose'の引数として使用します。 –

+0

それは動作します! しかし、最初にType1 .. Type3、 を宣言してから、ユニオンコンストラクタT1 .. T3を作成してから、そのタイプのType1 .. Type2にstaticの "matching"関数を追加する必要がありました。 これは間違いありませんか? – RobF