let init c1 c2 = Game [Hand (c1, c2)]
另一種情況是,當遊戲進行過程中,你應該只允許Hit
,但不Hand
,所以定義此過渡:
let hit (Game deals) card = Game (Hit card :: deals)
正如你所看到的,hit
的功能需要在現有Game
通過。
步驟3
什麼防止一個客戶端從創建一個無效Game
值,例如[Hand; Hit; Hand; Hit; Hit]
?
BlackJack.fsi:
您可以用signature file封裝上述狀態機
type Deal
type Game
val init : Card -> Card -> Game
val hit : Game -> Card -> Game
val card : Deal -> Card list
val cards : Game -> Card list
這裏,類型Deal
和Game
聲明,但他們的 '建設者' 不是。這意味着你不能直接創建這些類型的值。此,例如,不編譯:
let g = BlackJack.Game []
給出的錯誤是:
錯誤FS0039:該值,構造,命名空間或類型 '遊戲' 是沒有定義
創建Game
價值的唯一方法是調用,爲您創建它的功能:
let g =
BlackJack.init
{ Face = Ace; Suit = Spades }
{ Face = King; Suit = Diamonds }
這也使您能夠繼續遊戲:
let g' = BlackJack.hit g { Face = Two; Suit = Spades }
你可能已經注意到,上面的簽名文件還定義了兩個函數來獲取卡出Game
和Deal
值。這裏是實現:
let card = function
| Hand (c1, c2) -> [c1; c2]
| Hit c -> [c]
let cards (Game deals) = List.collect card deals
客戶端可以使用它們像這樣:
> let cs = g' |> BlackJack.cards;;
>
val cs : Card list = [{Suit = Spades;
Face = Two;};
{Suit = Spades;
Face = Ace;};
{Suit = Diamonds;
Face = King;}]
注意,這種方法主要是結構;有幾個移動部件。
附錄 這些是上面所用的文件:
Cards.fs:
namespace Ploeh.StackOverflow.Q34042428.Cards
type Suit = Diamonds | Hearts | Clubs | Spades
type Face =
| Two | Three | Four | Five | Six | Seven | Eight | Nine | Ten
| Jack | Queen | King | Ace
type Card = { Suit: Suit; Face: Face }
酒杯。FSI:
module Ploeh.StackOverflow.Q34042428.Cards.BlackJack
type Deal
type Game
val init : Card -> Card -> Game
val hit : Game -> Card -> Game
val card : Deal -> Card list
val cards : Game -> Card list
BlackJack.fs:
module Ploeh.StackOverflow.Q34042428.Cards.BlackJack
open Ploeh.StackOverflow.Q34042428.Cards
type Deal = Hand of Card * Card | Hit of Card
type Game = Game of Deal list
let init c1 c2 = Game [Hand (c1, c2)]
let hit (Game deals) card = Game (Hit card :: deals)
let card = function
| Hand (c1, c2) -> [c1; c2]
| Hit c -> [c]
let cards (Game deals) = List.collect card deals
Client.fs:
module Ploeh.StackOverflow.Q34042428.Cards.Client
open Ploeh.StackOverflow.Q34042428.Cards
let g =
BlackJack.init
{ Face = Ace; Suit = Spades }
{ Face = King; Suit = Diamonds }
let g' = BlackJack.hit g { Face = Two; Suit = Spades }
let cs = g' |> BlackJack.cards
感謝馬克。在fsi文件中,如果我們確實想明確地讓外部世界使用「遊戲」,我們將如何表達?它會在fsi文件中「鍵入Game()」嗎? –
@ScottNimrod如果你想這樣做,最簡單的方法是刪除'.fsi'文件,因爲那麼普通模塊聲明就會生效。否則,我肯定[文檔](https://msdn.microsoft.com/en-us/library/dd233196.aspx)可以告訴你如何做到這一點。 –