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

ank*_*981 7 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
Run Code Online (Sandbox Code Playgroud)

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

我很可能忽略了一些非常简单的东西,所以我很乐意向它解释.

Ale*_*kin 14

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

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

def join(a, b \\ nil, sep), do: "default b"
def join(a, b, sep \\ nil), do: "default sep"
Run Code Online (Sandbox Code Playgroud)

使编译器在调用时卡住join("hello", 42).

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

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