Reputation: 11595
I just don't understand what the compiler is trying to tell me here:
let someCard = getFirstCard hand
Error:
This expression was expected to have type
Card * Card
but here has type
(Card * Card) option
I then tried this:
let getFirstCard (hand:Card*Card) = function
| card1, card2 -> Some(card1)
But I get the same error.
I just don't get the Options template. I continue to struggle with this.
My code is below:
type Suit = | Spades| Clubs | Diamonds | Hearts
type Face = | Two | Three | Four | Five
| Six | Seven | Eight | Nine | Ten
| Jack | Queen | King | Ace
type Card = {Face:Face; Suit:Suit}
type Deal = | Hand of Card * Card
| Hit of Card
let private suits = [Spades; Clubs; Diamonds ; Hearts]
let private faces = [Two; Three; Four; Five; Six; Seven; Eight; Nine; Ten;
Jack; Queen; King; Ace]
let deck = [for suit in suits do
for face in faces do
yield {Face=face; Suit=suit}]
let hitPlayer (deck:Card list) =
(deck.Head, deck.Tail)
let shuffle xs =
let swap i j (array : _[]) =
let tmp = array.[i]
array.[i] <- array.[j]
array.[j] <- tmp
let rnd = System.Random()
let xArray = Seq.toArray xs
let n = Array.length xArray
for i in [0..(n-2)] do
let j = rnd.Next(i, n-1)
swap i j xArray
xArray |> Seq.toList
let deal = function
| card1::card2::remaining -> Some(card1, card2), remaining
| _ -> None, [];;
let getFirstCard (hand:Card*Card) = function
| card1, card2 -> card1
let hand, deckRemaining = deal (shuffle deck);;
let someCard = getFirstCard hand
Upvotes: 1
Views: 60
Reputation: 233125
The getFirstCard
function has the type Card * Card -> 'a * 'b -> 'a
(which, BTW, looks strange, to say the least). It does, however, expect its first parameter to be of the type Card * Card
.
hand
, on the other hand (pun intended), has the type (Card * Card) option
. This means that it may contain a Card * Card
value, but it also may not. You'll need to tell your program how to deal with both cases.
As we've discussed before, the Option type is an 'elevated world', and the most appropriate strategy is to stay in that elevated world until you can deal with all cases. Here's one way to do it:
let someCard = hand |> Option.map getFirstCard
This still doesn't work because of the weird implementation of getFirstCard
.
Looking at the implementation of getFirstCard
, though, I get the impression that what you attempt to do is to get the first card out of a tuple of cards. This, however, can be written as:
let getFirstCard (card1, card2) = card1
That function is already built into F#, although there's nothing wrong with giving it a domain-specific name. In that case, though, I'd suggest aliasing it instead:
let getFirstCard = fst
Given one of the two above definitions of getFirstCard
, the expression
let someCard = hand |> Option.map getFirstCard
gives you a someCard
value of the type Card option
. You'll notice that we've stayed in the 'elevated' Option world.
Specifically, though, someCard
has this value:
> someCard;;
val it : Card option = Some {Face = King;
Suit = Clubs;}
You'll note that it isn't just King of Clubs, but Some King of Clubs.
Upvotes: 4
Reputation: 528
Try this :
let getFirstCard (hand) =
match hand with
| Some(x) -> Some (fst x)
|_ -> None
let hand, deckRemaining = deal (shuffle deck);;
let someCard = getFirstCard hand
It compiles & runs for me.
Actually, function getFirstCard could be renamed as a generic fun on tuples :
let getFirstOfTupleOption tup =
match tup with
| Some (x) -> Some (fst x)
| _ -> None
Alternatively, you may want explicit type restriction on your domain with :
let getFirstCard (hand:(Card*Card) option) =
match hand with
| Some(x) -> Some (fst x)
|_ -> None
Upvotes: 1