Govinda Arjoon
Govinda Arjoon

Reputation: 65

How to compare values of a list and return true if all match?

I need to take a list of cards and check to see if their colors are the same. if they are return true otherwise return false. The function card_color is used to determine the color of a card.

When I try to implement with a recursive function called match_col and pattern matching I get several errors.

type Suit = Clubs | Diamonds | Hearts | Spades
type Rank = Jack | Queen | King | Ace | Num of int
type Card = Rank * Suit
type Color = Red | Black
type Move = Discard of Card | Draw

let card_color (c:Card) = 
  match c with
    | _, Clubs -> Black
    | _, Spades -> Black
    | _, Diamonds -> Red
    | _, Hearts -> Red

let rec match_col cs col = 
  match cs with
    | [] -> true
    | x::xs when col = card_color x -> match_col xs
    | x::xs when not col = card_color x -> false

let all_same_color cs =
  let col = card_color (cs[0])
  let res = match_col cs col
  res

I expect the function match_col to return true if the entire list has the same color as the first element in the list. If not then return false. However, the compiler throws:

fs(40,40): error FS0001:All branches of a pattern match expression must have the same type. This expression was expected to have type 'bool', but here has type 'Color-> bool'.

fs(41,28): error FS0001: This expression was expected to have type
    'bool'
but here has type
    'Color'

fs(45,23): error FS0001: This expression was expected to have type
    'Card list'
but here has type
    'int list -> Card'

Upvotes: 0

Views: 336

Answers (1)

Nghia Bui
Nghia Bui

Reputation: 3784

For the 1st error, your second branch is not returning bool, you should write:

| x::xs when col = card_color x -> match_col xs col

For the 2nd error, please note that not is actually a function, so it expects a bool value not a Color value, you should write:

| x::xs when not (col = card_color x) -> false

Compiler now still cannot make sure your matching is complete because it cannot know the function card_color is pure or impure. It will warn you warning FS0025: Incomplete pattern matches on this expression. So, you should write:

let rec match_col cs col =
  match cs with
    | [] -> true
    | x::xs when col = card_color x -> match_col xs col
    | _ -> false

But going through a list and checking if there is an element satisfied a condition is already supported by the List module. So, you could write:

let match_col cs col =
    cs |> List.exists (fun x -> card_color x <> col) |> not

Finally, to access an element of a list, you should use the dot notation: cs.[0] not cs[0]. But when using the dot notation, you have to provide type annotation, so we have to write:

let all_same_color (cs : Card list) =
    let col = card_color cs.[0]
    let res = match_col cs col
    res

Another way to write without dot notation:

let all_same_color cs =
    let col = card_color (cs |> List.head)
    let res = match_col cs col
    res

Upvotes: 2

Related Questions