6

我正在编写一个创建一副纸牌的 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

3 回答 3

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(_) -> ...

您甚至可以定义一些活动模式来获得红/黑卡。

于 2012-12-12T07:37:21.697 回答
4

枚举是表示卡片的好选择。您可以免费比较西装和等级之间的比较,并轻松地将枚举从/转换为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) ]

如果您选择有区别的联合,则必须手动制作所有suits 和所有ranks 的列表。优点是 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) ]
于 2012-12-12T07:16:35.427 回答
3

作为垫答案的附录,您还可以使用反射来生成甲板:

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) ]
于 2012-12-12T18:19:55.187 回答