F # how to add type to list?
So I am trying to create a card game for a school project with F #. I am coming from C # and have trouble understanding things in F #. I have a type
Player = {Name : String; Hand : Card list}
that represents the player
then I have a deck that has cards inside. How to transfer the first card from the deck to the players hand? In C #, I would use something like removeat[i]
.
let returnFirstElement list =
match list with
| h::t -> Some(h),t
| [] -> None,[]
Pass your list and it will return a tuple. The first value will be your card, the second will be the rest of the deck. Using Some and None there is like running out of cards in the deck, then you won't get a card back. As you from a C # background think of as a nullable Some
type and None
as null. Take a look at F # Some
and None
if you're not sure what are the most common uses for them.
You can use this like
let (topCard, restOfDeck) = returnFirstElement deckOfCards
May be of extra help if needed, but this should be a good enough start.
To write idiomatic functional code in F #, you need to think about how to explicitly model system state. Each player has a hand of cards that represent part of the state, but we also need to simulate the state of the deck.
Logically, drawing from a deck affects both the player's hand and the deck.
We also need to consider the error case where there are no cards in the deck.
Here's a simple example: just mistakes when there are no cards in the deck.
type Player = {Name : string; Hand : Card list}
let draw player deck =
match deck with
|[] -> invalidArg "deck" "No cards in deck!"
|drawn::rest -> ({ player with Hand = drawn :: player.Hand }, rest)
You also pass the Player
deck represented by the function Card list
to the draw function, and it returns you a new one Player
with the card taken from the deck and a new one Card list
without the card that was drawn.
For some games, you might be better off having two lists of cards, one drawable, one trash. Then, when you run out of cards, you can create a new deck by shuffling the throws.
You can of course use anything .Net in F #. It's not idiomatic F #, but again, it's a moot point about how much recursion is. Basically, if you want to remove an item from an F # list, the F # list might not be the best collection to use. You can of course apply filter
to it at any time. But if all of your items are unique, consider using a set.
Here's the version with .RemoveAt:
open System.Collections.Generic
let xs = ResizeArray [1;2;3]
xs.RemoveAt(2)
xs
ResizeArray is a synonym for C # list.
Relatively simple movement of the first card and the rest you can use the "tail" and "head" functions.