2012-12-12 31 views
5

Tôi đang làm việc trên một hướng dẫn F # tạo ra một cỗ bài. Các loại được liệt kê, nhưng tôi không thể hiểu cách lặp qua các loại để tạo bản đồ của toàn bộ boong. Tôi dự kiến ​​sẽ làm một cái gì đó nhưF # Loại và Looping

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

Không có cách nào để làm điều này? Dưới đây là các loại được tạo.

Tôi nghĩ rằng nếu tôi đã thay đổi họ từ các loại vào danh sách họ có thể công đoàn, phải không? Vì vậy, điểm của các loại là gì?

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

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

type deck= Deck of ranks * suits 

Trả lời

4

Enums là lựa chọn tốt để đại diện cho thẻ. Bạn có so sánh giữa các bộ quần áo và trong số các cấp bậc miễn phí và dễ dàng chuyển đổi các enums từ/thành 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) ] 

Nếu bạn đi cho discriminated unions, bạn phải tự làm cho danh sách của tất cả các suit s và tất cả rank s. Ưu điểm là phù hợp với mô hình tốt hơn của DU hơn là của enums.

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

dus cũng cung cấp so sánh "miễn phí" (dựa trên trường hợp thứ tự). – Daniel

+0

Tôi không nghĩ rằng enum là một lựa chọn tốt. Bạn thậm chí có thể thay đổi giá trị vòng lặp thành "-10..20" và "0..6" và mã của bạn vẫn tạo một số "thẻ" không hợp lệ. Và như đã nói, bạn cũng có so sánh về DU miễn phí như enums. –

5

Một cách tiếp cận khác trong đó sử dụng một sự kết hợp kỳ thị mà mắt lưới độc đáo hơn enums với 's F # cú pháp

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)) 

Sau đó, bạn có thể làm một số mô hình gọn gàng phù hợp như

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

Bạn có thể thậm chí xác định một số mẫu đang hoạt động để nhận thẻ đỏ/đen.

+1

Bạn quên 'Valcard (10)'; đó là nhược điểm với việc liệt kê tất cả các giá trị theo cách thủ công. – pad

+0

@pad - tốt đốm - chuyển sang bản đồ trên danh sách –

+1

Lưu ý rằng 'ValCard của int' là một trừu tượng bị rò rỉ vì' ValCard 0' và 'ValCard 11', vv là các giá trị bất hợp pháp. – pad

2

Là một phụ lục để trả lời pad, bạn cũng có thể sử dụng phản ánh để tạo ra boong:

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) ]