2

I'm trying to write a recursive function for building a specialized card deck. The first parameter, numOfCards is supposed to be the number of cards in the deck. The sourceDeck is a list of possible cards that can be used to build the deck and the currentDeck is my accumulator, which results in the final list of cards.

However, the problem I have is that when I send in a number value for numOfCards it gets set to 0 in the match statement. Or at least that's how it looks. I tried stepping through with the debugger, and when I enter the function, the value is correct. As soon as I start executing the match, however, it suddenly becomes 0, both if I hover over the value in the match and over the value in the parameters (which is at least consistent).

As such, the match triggers on 0 and just returns the empty currentDeck, rather than iterating.

Any tips on this one? Probably something simple, but I'm stumped. :)

let rec buildDungeon (numOfCards, sourceDeck : List<Card>, currentDeck : List<Card>) =
  match currentDeck.Length with
    | numOfCards  -> currentDeck
    | _           -> buildDungeon (numOfCards, sourceDeck, newCard(sourceDeck)::currentDeck)
4

3 回答 3

5

If you want to handle a case when currentDeck.Length equals numOfCards then you need to write:

let rec buildDungeon (numOfCards, sourceDeck : List<Card>, currentDeck : List<Card>) =
  match currentDeck.Length with
  | n when n = numOfCards -> currentDeck
  | _ -> buildDungeon (numOfCards, sourceDeck, newCard(sourceDeck)::currentDeck)

The problem is that when you write a clause | numOfCards -> (...), the pattern matching binds the value of currentDeck.Length to the symbol numOfCards (and the newly defined numOfCards value hides the previous value of the same name - that is, the value you got as a parameter).

The pattern matching I wrote above binds currentDeck.Length to a new symbol n and then checks that n = numOfCards (referring to the numOfCards passed as an argument).

So, pattern matching is not really the best tool for checking equality - and your code could be probably more easily written using normal if:

let rec buildDungeon (numOfCards, sourceDeck : List<Card>, currentDeck : List<Card>) =
  if currentDeck.Length = numOfCards then currentDeck
  else buildDungeon (numOfCards, sourceDeck, newCard(sourceDeck)::currentDeck)
于 2012-11-21T23:56:06.107 回答
1

The numOfCards in the match expression is not the same as the one in the parameters: it's a new variable that's shadowing the old one. Since it's an unbounded variable pattern, it will match anything at all and bind itself to that thing. Thus, the second (wildcard) pattern is never reached, because the first one never fails.

于 2012-11-21T23:55:33.880 回答
1

As far as I understand pattern matching in F# you should use

let rec buildDungeon (numOfCards, sourceDeck : List<Card>, currentDeck : List<Card>) =
  match currentDeck.Length with
  | n when n = numOfCards -> currentDeck
  | _ -> buildDungeon (numOfCards, sourceDeck, newCard(sourceDeck)::currentDeck)

By specifying the pattern sort of create new variables (n in this example). You are not using the already defined.

于 2012-11-22T00:01:58.557 回答