2012-12-12 27 views
5

Pracuję nad samouczkiem F #, który tworzy talię kart. Typy są wymienione, ale nie mogę zrozumieć, jak przechodzić między typami, aby utworzyć mapę całej talii. Spodziewałem się zrobić coś takiego jakF # Typy i zapętlanie

Foreach rank in ranks 
    Foreach suit in suits 
     somehow combine the two 
    next suit 
next rank 

Nie ma sposobu, aby to zrobić? Poniżej znajdują się typy utworzone.

Myślę, że gdybym zmienił je z typów na listy, mogłyby połączyć, prawda? Jaki jest sens typów?

type suits= 
    |Spade=1 
    |Heart=2 
    |Club=3 
    |Diamond=4 

type ranks= 
    |ValCard of int 
    |Jack 
    |Queen 
    |King 

type deck= Deck of ranks * suits 

Odpowiedz

4

Enums to dobry wybór do reprezentowania kart. Masz porównanie między kolorami i wśród rang za darmo i łatwo konwertuj wyliczenia z/na int.

type suit = 
    | Spade = 1 
    | Heart = 2 
    | Club = 3 
    | Diamond = 4 

type rank = 
    | Ace = 1 | Two = 2 | Three = 3 | Four = 4 | Five = 5 | Six = 6 | Seven = 7 
    | Eight = 8 | Nine = 9 | Ten = 10 | Jack = 11 | Queen = 12 | King = 13 

/// 'Card' is a type which represents a particular card  
type Card = Card of rank * suit 

/// 'deck' is a list consisting of all cards in a full deck 
let deck = [ for r in 1..13 do 
       for s in 1..4 do 
       yield Card(enum<rank> r, enum<suit> s) ] 

Jeśli pójdziesz do discriminated unions, musisz ręcznie zrobić listę wszystkich suit S i wszystkie rank s. Zaletą jest lepsze dopasowanie wzorców do DU niż do wyliczenia.

type suit = 
    | Spade 
    | Heart 
    | Club 
    | Diamond 

type rank = | Ace | Two | Three | Four | Five | Six | Seven 
      | Eight | Nine | Ten | Jack | Queen | King 

type Card = Card of rank * suit 

let private suits = [Spade; Heart; Club; Diamond] 
let private ranks = [Ace; Two; Three; Four; Five; Six; Seven; 
        Eight; Nine; Ten; Jack; Queen; King] 

let deck = [ for rank in ranks do 
       for suit in suits do 
       yield Card(rank, suit) ] 
+2

dalsi zapewniają również porównanie „za darmo” (na podstawie kolejności przypadku). – Daniel

+0

Nie sądzę, że enum to dobry wybór. Możesz nawet zmienić wartości w pętli na "-10..20" i "0..6", a Twój kod nadal tworzy nieprawidłowe "karty". I jak już wspomniano, masz również porównanie na DU za darmo, jak na przykład. –

5

Alternatywnym podejściem, które wykorzystuje dyskryminowanych unii które zazębia się bardziej estetycznie niż teksty stałe z F # 's składni

type suit= 
    |Spade 
    |Heart 
    |Club 
    |Diamond 
    static member all = [Spade;Heart;Club;Diamond] 

type rank= 
    |ValCard of int 
    |Jack 
    |Queen 
    |King 
    static member all =([1..10]|> List.map (ValCard)) @ [Jack;Queen;King] 

type card = |Card of rank * suit 

let all_cards = suit.All |> List.collect (fun s -> rank.all |> List.map (fun r -> Card(r,s)) 

Następnie można zrobić kilka schludny wzorzec dopasowania jak

all_cards 
|> List.iter (fun c -> 
    match c with 
    |Card(King,Spade) -> ... 
    |Card(King,_) -> ... 
    |Card(_) -> ... 

można nawet Zdefiniuj aktywne wzorce, aby uzyskać czerwone/czarne karty.

+1

Zapomniałeś o Valcard (10) '; jest to wada z ręcznym wymienianiem wszystkich wartości. – pad

+0

@pad - dobre plamienie - przełączono na mapę na liście –

+1

Należy zauważyć, że 'ValCard of int' jest nieszczelną abstrakcją, ponieważ' ValCard 0' i 'ValCard 11', itd. Są niedozwolonymi wartościami. – pad

2

Jako dodatek do odpowiedzi tamponu, można również użyć refleksji do generowania talię:

type Union<'T> private() = 
    static member val Cases = 
    FSharpType.GetUnionCases(typeof<'T>) 
    |> Array.map (fun case -> FSharpValue.MakeUnion(case, null) :?> 'T) 

let deck = 
    [ for rank in Union<rank>.Cases do 
     for suit in Union<suit>.Cases do 
     yield Card(rank, suit) ]