将列表传递给函数时,Elixir中的Arity问题

时间:2018-01-10 20:17:23

标签: syntax functional-programming elixir

我是Elixir的新手(和功能性的)。我正在构建一个玩具扑克游戏,以便更熟悉该语言。当我编译此代码时,我收到以下错误:

** (BadArityError) #Function<12.99386804/2 in :erl_eval.expr/5> with arity 2 
called with 1 argument ('SK')

每当我将列表作为参数传递时,似乎都会发生这种情况。错误发生在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)])

这是语言的一部分吗?或者我犯了错误?

2 个答案:

答案 0 :(得分:4)

我可以看到您的代码存在两个问题:

首先,这一行

 def burn_cards(current_hand, cards = []) do

意味着传入的第二个参数必须是空列表,但是您没有传入一个空列表,而是传递一个包含一个元素的列表。我相信你想用这个来代替

  def burn_cards(current_hand, cards \\ []) do

表示默认值为空列表(如果省略),但也接受包含元素的列表。

其次是过滤部分

 Enum.filter(current_hand, fn (x, cards) -> x not in cards end)

你不应该有卡片。相反,你应该尝试

 Enum.filter(current_hand, fn (x) -> x not in cards end)

答案 1 :(得分:0)

我相信你的问题是传递给Enum.filter/2的匿名函数的第二个参数。 看来这个函数必须只接收一个参数。这是,我们可以这样做:

iex(3)> pairs = [2, 4]                               
[2, 4]
iex(4)> Enum.filter([1, 2, 3, 4, 5], fn (x) -> x in pairs  end)    
[2, 4]

但不是这样:

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

此问题的解决方案是使用第一种形式。那么你的Enum.filter电话 可能看起来像这样:

Enum.filter(current_hand, fn (x) -> x not in cards end)

另外,我还有另一个问题:

** (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

这种情况正在发生,因为匹配cards = []只有当卡片成功时才会成功 也是一个空列表。所以你的函数调用

Hand.burn_cards(hand, [Enum.at(hand, 0)])

永远不会匹配。您可能希望定义burn_cards/2之类的

def burn_cards(current_hand, cards) do
  Enum.filter(current_hand, fn (x) -> x not in cards end)
end

或者,如果你真的想确保cards是一个列表,你可以这样做

def burn_cards(current_hand, cards) when is_list(cards) do
  Enum.filter(current_hand, fn (x) -> x not in cards end)
end

希望我能提供帮助。 =)