2016-09-10 5 views
5

が、私はそうのようなDUがあるとします。差別化された共用体型のリストが同じケースであるかどうかをどのように判断できますか?

type DU = Number of int | Word of string 

そして、私はそれらのリストを作成するとします。

[Number(1); Word("abc"); Number(2)] 

どのように私はすべてのDUのリストについては、trueを返します関数を記述することができます要素は同じ場合です。上記のリストの場合、falseを返すはずです。

+3

ヒント:最初の2つが同じ場合であれば2未満のアイテムを含むリストは、そうでなければ 'true'をを返す必要があり、また、リストの末尾が' true'をを返し、最終的な結果はまた、 'true'をなければなりません。 *(ヒント2:この関数を書いた後、 'List'モジュールの関数を使って物事を少しでも活用できるかどうか検索してください)* – Sehnsucht

+0

あなたがここに示した2つのケース以上のユニオンタイプに関する質問はありますか?私は何かが欠けていない限り、プレイにどのように多くのケースである –

+0

@AntonSchwaighoferは、「どのように私は、リストのすべての要素が同じである知っています」と – Sehnsucht

答えて

5

私がここで使用したい一般的なアプローチは、ケースを識別タグに労働組合の値をマッピングして、タグの結果セットが最大1つの要素を持っているかどうかを確認することです。

タグ付け機能については
let allTheSameCase (tagger: 'a -> int) (coll: #seq<'a>) = 
    let cases = 
     coll 
     |> Seq.map tagger 
     |> Set.ofSeq 
    Set.count cases <= 1 

、あなたが手でタグを割り当てることができます。

allTheSameCase (function Number _ -> 0 | Word _ -> 1) lst 

または使用リフレクション(あなたは、必要に応じて結合フラグを設定する必要があることに注意してください):

open Microsoft.FSharp.Reflection 

let reflectionTagger (case: obj) = 
    let typ = case.GetType() 
    if FSharpType.IsUnion(typ) 
     then 
      let info, _ = FSharpValue.GetUnionFields(case, typ) 
      info.Tag 
     else -1 // or fail, depending what makes sense in the context. 
+0

遅れた返事のお詫び。これは私のために働いた、ありがとう:) –

+1

@DavidNg:クール、それを聞いてうれしい。それが助けられたら、答えを受け入れたものとしてマークしてください。 – scrwtp

4

リストの要素が特定の共用体のケースであることを確認したい場合は、述語関数を提供するのが簡単です。

let isNumbers = List.forall (function Number _ -> true | _ -> false) 

あなたがどのユニオンのケースに関わらず気にしないのであれば、それらがすべて同じであれば、それらをすべて明示的に綴る必要があります。反射マジックがF#の中で公開されていないプロパティを取得しないようにするには、各ケースに値を割り当てる必要もあります。任意の値を考える必要を避けるために、裏側の異なるDUにマップするアクティブパターンを使用できます。

let (|IsNumber|IsWord|) = function 
| Number _ -> IsNumber 
| Word _ -> IsWord 

let isSameCase src = 
    src |> Seq.groupBy (|IsNumber|IsWord|) |> Seq.length <= 1 
関連する問題