多个子句中函数头的需求是什么?

时间:2016-12-28 06:20:41

标签: elixir

我是Elixir的新手并且坦率地说,当我们有多个具有默认值的子句时,无法理解为什么需要函数头。来自官方文档:

  

如果具有默认值的函数具有多个子句,则它是必需的   创建一个函数头(没有实际的主体)来声明   默认值:

defmodule Concat do
  def join(a, b \\ nil, sep \\ " ")

  def join(a, b, _sep) when is_nil(b) do
    a
  end

  def join(a, b, sep) do
    a <> sep <> b
  end
end

IO.puts Concat.join("Hello", "world")      #=> Hello world
IO.puts Concat.join("Hello", "world", "_") #=> Hello_world
IO.puts Concat.join("Hello")               #=> Hello

我读了这个,我就像“为什么?”。这取得了什么成果?这并不是两个子句不明确,编译器也无法推断出正确的调用。此外,我只是看不到添加函数头如何帮助。

我很可能忽略了一些非常简单的事情,所以我很乐意向我解释。

2 个答案:

答案 0 :(得分:12)

Erlang函数(以及Elixir函数)由两个实体定义:name和arity。在您的示例中,def join(a, b \\ nil, sep \\ " ")仍然是arity 3,当编译器找到类似join("hello", "world")的调用时,她知道它应该路由到join/3,并传递{{1} }}作为第二个参数,并使用第三个参数的默认值。

如果我们被允许在函数体中指定默认参数,而没有这个函数头,我们最终会得到:

"world"

使编译器在调用def join(a, b \\ nil, sep), do: "default b" def join(a, b, sep \\ nil), do: "default sep" 时卡住。

请注意,如果且只有一个或多个功能签名具有默认参数,则会要求您提供头功能。

head函数的目标是在没有默认参数值(join("hello", 42)的情况下调用时显式定义签名。)

答案 1 :(得分:2)

您从中获得的唯一具体好处是您的默认参数将应用于所有函数调用。如果编译器允许您按照建议的方式执行,则等效项将如下所示:

def join(a, b \\ nil, _sep \\ " ") when is_nil(b) do
    a
end

def join(a, b \\ nil, _sep \\ " ") do
    a <> sep <> b
end

根据我的理解,它的目的只是为了减少默认情况下可能出现的混乱。