2012-12-12 7 views
5

私は、カードのデッキを作成するF#チュートリアルに取り組んでいます。タイプはリストされていますが、フルデッキのマップを作成するためにタイプをループする方法を理解できません。私は何かをすることを期待F#タイプとループ

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

これを行う方法はありますか?以下は作成されるタイプです。

私がそれらを型からリストに変更すれば、彼らは組合ができたと思いますよね?だから、タイプのポイントは何ですか?

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

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

type deck= Deck of ranks * suits 

答えて

4

Enumsは、カードを表すのに適しています。あなたはスーツとランクの間で無料で比較し、enumを/から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) ] 

あなたがdiscriminated unionsのために行く場合は、手動ですべてのsuit秒のリストとすべてrankのを確認する必要があります。利点は、列挙型よりもDUのパターンマッチングが優れていることです。

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

川下ユーザーはまた、(ケースの順序に基づいて)「自由のための」比較を行います。 – Daniel

+0

私はenumが良い選択だとは思わない。ループ値を "-10..20"と "0..6"に変更することもできますが、コードでは無効な "カード"が作成されます。そして、指摘したように、あなたは列挙型のように無料でDU上で比較を行うこともできます。 –

5

F#の構文

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

と列挙型よりもうまく噛み合って区別組合を使用して別のアプローチは、その後、あなたのようなマッチングいくつかのきちんとしたパターンを行うことができます

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

あなたも可能性赤色/黒色のカードを得るためにいくつかのアクティブなパターンを定義します。パッドの答えに補遺として

+1

あなたはValcard(10)を忘れました。すべての値を手動でリストすることは欠点です。 – pad

+0

@pad - 良いスポッティング - リストの地図に切り替えました –

+1

「ValCard of int」は、「ValCard 0」や「ValCard 11」などが不正な値であるため、抽象的な抽象化であることに注意してください。 – pad

2

、あなたはまたデッキを生成するためにリフレクションを使用することができます。

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