Scott Nimrod
Scott Nimrod

Reputation: 11595

Unable to resolve error regarding "option" when retrieving value from tuple

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

Answers (2)

Mark Seemann
Mark Seemann

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

FZed
FZed

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

Related Questions