2016-09-10 22 views
5

Załóżmy, że mam DU tak:Jak ustalić, czy lista dyskryminowanych rodzajów związków jest taka sama?

type DU = Number of int | Word of string 

I załóżmy utworzyć listę z nich:

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

Jak mogę napisać funkcję, która zwraca wartość true dla listy DU gdzie wszystkich elementy są tym samym przypadkiem. Dla powyższej listy powinien zwracać wartość false.

+3

wskazówka: lista mniej niż 2 nie powróci 'true' inaczej gdy dwa są takie same, oraz również ogon listy zwraca' TRUE to wynik końcowy powinien być 'TRUE . * (podpowiedź2: po wpisaniu tej funkcji wyszukaj, czy możesz użyć funkcji w module 'List', aby trochę wykorzystać) * – Sehnsucht

+0

Czy pytanie dotyczy typów związków z więcej niż 2 przypadkami, które tu pokazujesz? –

+0

@AntonSchwaighofer, chyba że czegoś brakuje, ile przypadków jest w grze, nie ma znaczenia – Sehnsucht

Odpowiedz

5

Ogólne podejście, którego użyłbym tutaj, to odwzorowanie wartości związków na tagi identyfikujące przypadki, a następnie sprawdzenie, czy wynikowy zestaw znaczników ma co najwyżej jeden element.

let allTheSameCase (tagger: 'a -> int) (coll: #seq<'a>) = 
    let cases = 
     coll 
     |> Seq.map tagger 
     |> Set.ofSeq 
    Set.count cases <= 1 

Dla funkcji Taggera można przypisać tagi ręcznie:

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

lub wykorzystanie odbicie (zauważ, że może trzeba ustawić wiązania flagi w razie potrzeby):

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

Przeprosiny za spóźnioną odpowiedź. To zadziałało dla mnie, dzięki :) –

+1

@DavidNg: cool, cieszę się, że to słyszę. Jeśli to pomogło, zaznacz odpowiedź jako zaakceptowaną. – scrwtp

4

Jeśli chcesz sprawdzić, czy elementy listy mają określony przypadek związku, można łatwo udostępnić funkcję predykatu.

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

Jeśli nie obchodzi Cię, która sprawa związkowa, o ile wszystkie są takie same, musisz je przeliterować jawnie. Jeśli nie masz do czynienia z magią odbicia w F #, musisz przypisać pewną wartość do każdego przypadku. Aby uniknąć wymyślania dowolnych wartości, możemy zastosować aktywny wzorzec, który za kulisami odwzorowuje innego DU.

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

let isSameCase src = 
    src |> Seq.groupBy (|IsNumber|IsWord|) |> Seq.length <= 1 
Powiązane problemy