Reputation: 463
I'm new to Elixir (and functional). I'm building a toy poker game to get more familiar with the language. When I compile this code, I get the following error:
** (BadArityError) #Function<12.99386804/2 in :erl_eval.expr/5> with arity 2
called with 1 argument ('SK')
Which seems to happen whenever I pass a list as an argument. The error is occurring inside Hand.burn_cards
.
import Enum
defmodule Deck do
def create do
for rank <- '23456789TJQKA', suit <- 'CDHS', do: [suit,rank] |> shuffle
end
def deal(deck, n) do
deck
|> shuffle
|> take(n)
end
end
defmodule Hand do
def burn_cards(current_hand, cards = []) do
Enum.filter(current_hand, fn (x, cards) -> x not in cards end)
end
end
hand = Deck.deal(deck = Deck.create, 5)
deck = deck -- hand
Hand.burn_cards(hand, [Enum.at(hand, 0)])
Is this part of the language? Or am I making a mistake?
Upvotes: 1
Views: 1277
Reputation: 1870
I believe your problem is the second parameter on the anonymous function passed to Enum.filter/2
.
It seems this function must receive only one argument. This is, we could do this:
iex(3)> pairs = [2, 4]
[2, 4]
iex(4)> Enum.filter([1, 2, 3, 4, 5], fn (x) -> x in pairs end)
[2, 4]
But not this:
iex(5)> pairs
[2, 4]
iex(6)> Enum.filter([1, 2, 3, 4, 5], fn (x, pairs) -> x in pairs end)
** (BadArityError) #Function<12.118419387/2 in :erl_eval.expr/5> with arity 2 called with 1 argument (1)
(elixir) lib/enum.ex:2857: Enum.filter_list/2
The solution to this problem is to use the first form. So your Enum.filter
call
could look like this:
Enum.filter(current_hand, fn (x) -> x not in cards end)
Also, I had another problem:
** (FunctionClauseError) no function clause matching in Hand.burn_cards/2
The following arguments were given to Hand.burn_cards/2:
# 1
['7S', 'S5', 'S4', 'D7', 'H7']
# 2
['7S']
help.exs:16: Hand.burn_cards/2
(elixir) lib/code.ex:376: Code.require_file/2
This was happening because the match cards = []
only succeeds when cards is
also an empty list. So your function call
Hand.burn_cards(hand, [Enum.at(hand, 0)])
will never match. You may want to define burn_cards/2
like
def burn_cards(current_hand, cards) do
Enum.filter(current_hand, fn (x) -> x not in cards end)
end
Or, if you really want to ensure cards
is a list, you can do
def burn_cards(current_hand, cards) when is_list(cards) do
Enum.filter(current_hand, fn (x) -> x not in cards end)
end
Hope I could help. =)
Upvotes: 0
Reputation: 2701
I can see two issues with your code:
first, this line
def burn_cards(current_hand, cards = []) do
implies that the second argument passed in must be empty list but you are not passing in an empty list, you are passing a list with one element. I believe you want to use this instead
def burn_cards(current_hand, cards \\ []) do
which means that default value is empty list if omitted, but also accepts lists with elements.
And secondly the filtering part
Enum.filter(current_hand, fn (x, cards) -> x not in cards end)
you should not have cards in there. Instead you should try
Enum.filter(current_hand, fn (x) -> x not in cards end)
Upvotes: 4