1

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
ildjarn
  • 62,044
  • 9
  • 127
  • 211
Scott Nimrod
  • 11,206
  • 11
  • 54
  • 118
  • BTW, that `shuffle` function looks like it could be simpler. See here for alternatives: http://stackoverflow.com/q/33312260/126014 – Mark Seemann Dec 19 '15 at 21:33

2 Answers2

4

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.

Community
  • 1
  • 1
Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
1

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
FZed
  • 520
  • 3
  • 10
  • Your definition of `getFirstCard` is equivalent to just `Option.map fst`. – Fyodor Soikin Dec 19 '15 at 20:17
  • Thanks Fyodor. It would be definitely be more elegant & succint. I still leave my answer unchanged and hope that OP will see your comment. – FZed Dec 19 '15 at 20:20