【问题标题】:tail recursive call in elixir and default parameters长生不老药中的尾递归调用和默认参数
【发布时间】:2014-03-06 15:38:40
【问题描述】:

我正在用 Elixir 写一个简单的例子,虽然它有效,但我并不真正理解如何。

defmodule MyList do
  def sum([],acc \\ 0), do: acc
  def sum([head | tail], acc), do: sum(tail,acc + head)
end

当我调用 MyList.sum 时,我得到了预期的结果

sum([]) => 0
sum([1,2,3]) => 6

我无法在第二个总和中添加默认参数,因为编译器会抛出错误

def sum/2 has default values and multiple clauses, use a separate clause for declaring defaults

所以我的问题是, sum([1,2,3]) 是如何工作的?它与任何定义都不匹配。 函数还是尾递归吗?

【问题讨论】:

  • 我想知道这是否是尾递归或不是我自己。我认为它可能是,因为您没有坚持任何应该强制代码创建堆栈框架的东西。
  • 它是尾递归的。我已经更新了回复。

标签: recursion pattern-matching default tail-recursion elixir


【解决方案1】:

当您有一个带有可选参数的多子句时,您可以将默认值指定为无正文子句:

defmodule MyList do
  def sum(list, acc \\ 0) # sets up default arguments

  def sum([],acc), do: acc
  def sum([head | tail], acc), do: sum(tail,acc + head)
end

关于您的示例,我只是猜测,但我认为您的代码相当于以下内容:

defmodule MyList do
  # implicitly generated due to default argument
  def sum(list), do: sum(list, 0)

  def sum([],acc), do: acc
  def sum([head | tail], acc), do: sum(tail,acc + head)
end

这就是为什么sum([1,2,3]) 也能正常工作的原因。

编辑: 该函数绝对是尾递归的。如果一个函数做的最后一件事是调用另一个函数(或它自己),那么它就是一个尾调用。所以在这种情况下,当我们调用sum(tail, acc + head)时,首先计算参数,然后进行尾递归调用。

【讨论】:

  • 那么,关于我的问题,默认参数是从第一个定义继承到其余的吗?看起来这就是正在发生的事情,它可以解释为什么定义无正文子句有效
  • 是的,默认参数是继承的(或者说是传递的)。第二个 sn-p 解释了这一点。该 sn-p 中的代码是原始代码的扩展等效项。函数sum/1 将调用sum/2 发送0 作为第二个参数。所以每个sum/2 子句都会收到这个默认值。 Body-less 子句做同样的事情,但它看起来更明确和更清晰,因为默认值是从任何子句中取出并在顶部单独指定的。
猜你喜欢
  • 2016-02-01
  • 2019-11-29
  • 1970-01-01
  • 2019-08-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-16
  • 1970-01-01
相关资源
最近更新 更多