我在Elixir的example中看到了这段代码:
defmodule Recursion do
def print_multiple_times(msg, n) when n <= 1 do
IO.puts msg
end
def print_multiple_times(msg, n) do
IO.puts msg
print_multiple_times(msg, n - 1)
end
end
Recursion.print_multiple_times("Hello!", 3)
我在这里看到使用不同参数定义两次的相同函数,我想了解这种技术。
我可以在重载函数中查看它们吗?
它是具有不同行为的单个函数,还是这两个不同的函数,如print_only_once
和print_multiple_times
?
这些功能无论如何都是联系在一起的?
答案 0 :(得分:3)
通常在函数式语言中,函数由子句定义。例如,在命令式语言中实现Fibonacci的一种方法是以下代码(不是最佳实现):
def fibonacci(n):
if n < 0:
return None
if n == 0 or n == 1:
return 1
else:
return fibonacci(n - 1) + fibonacci(n - 2)
要在Elixir中定义函数,您将执行以下操作:
defmodule Test do
def fibonacci(0), do: 1
def fibonacci(1), do: 1
def fibonacci(n) when n > 1 do
fibonacci(n-1) + fibonacci(n - 2)
end
def fibonacci(_), do: nil
end
Test.fibonacci/1
只是一个功能。具有四个子句和arity为1的函数。
_
。子句按声明的顺序进行评估,因此Test.fibonacci(2)
在前2个子句中失败并与第3个子句匹配,因为2 > 1
。
将子句视为更强大的if
语句。代码看起来更干净。并且对递归非常有用。例如,地图实现(该语言已经在Enum.map/2
中提供了一个):
defmodule Test do
def map([], _), do: []
def map([x | xs], f) when is_function(f) do
[f.(x) | map(xs, f)]
end
end
x
,列表的其余部分(尾部)是xs
,f
是一个函数。它将函数应用于第一个元素,并以列表的其余部分递归调用map。致电Test.map([1,2,3], fn x -> x * 2 end)
将为您提供以下输出[2, 4, 6]
因此,Elixir中的函数定义了一个或多个子句,其中每个子句与其余子句具有相同的arity。
我希望这能回答你的问题。
答案 1 :(得分:1)
在您发布的示例中,函数的两个定义具有相同数量的参数:2,此“when”事物是一个保护,但您也可以使用多个参数定义。首先,警卫 - 它们用于表达不能仅仅是匹配的内容,如下面的第二行:
def fac(0), do: 1
def fac(n), when n<0 do: "no factorial for negative numbers!"
def fac(n), do: n*fac(n-1)
- 因为仅仅通过相等/匹配来表达负数是不可能的。
这个 fac 是一个单一的定义,只有三种情况。请注意在参数位置使用常量“0”的酷感:) 你可以把它想象成更好的写作方式:
def fac(n) do
if n==0, do: 1, else: if n<0, do: "no factorial!", else: n*fac(n-1)
end
或开关盒(甚至看起来非常接近上面):
def fa(n) do
case n do
0 -> 1
n when n>0 -> n*fa(n-1)
_ -> "no no no"
end
end
只是“看起来更花哨”。事实上,事实证明,某些定义(例如解析器,小型解释器)在前者中看起来比后者更好。 Nb守卫表达非常有限(我认为你不能在守卫中使用你自己的功能)。
现在真实的,不同数量的论点 - 检查出来!
def mutant(a), do: a*a
def mutant(a,b), do: a*b
def mutant(a,b,c), do: mutant(a,b)+mutant(c)
e.g。
iex(1)> Lol.mutant(2)
4
iex(2)> Lol.mutant(2,3)
6
iex(3)> Lol.mutant(2,3,4)
22
它在方案中的作用有点类似(lambda arg ...) - 认为变异体将其所有参数作为列表并在其上进行匹配。但这一次,长生不老药将突变体视为3种功能,突变体/ 1 ,突变体/ 2 和突变体/ 3 ,并将它们称为这样
所以,回答你的问题:这些不像重载函数,而是分散/分散的定义。您可以在miranda,haskell或sml等函数式语言中看到类似的语言。