gpt4 book ai didi

erlang - Elixir 中为什么有两种函数?

转载 作者:行者123 更新时间:2023-12-03 02:24:53 25 4
gpt4 key购买 nike

我正在学习 Elixir,想知道为什么它有两种类型的函数定义:

  • 使用 def 在模块中定义的函数,使用 myfunction(param1, param2) 调用
  • 使用 fn 定义的匿名函数,使用 myfn.(param1, param2) 调用

只有第二种函数看起来是一等对象,可以作为参数传递给其他函数。模块中定义的函数需要包装在 fn 中。有一些语法糖看起来像 otherfunction(&myfunction(&1, &2)) 为了使这变得简单,但为什么首先有必要呢?为什么我们不能直接执行otherfunction(myfunction))?是否只允许像 Ruby 中那样调用不带括号的模块函数?它似乎继承了Erlang的这个特性,Erlang也有模块功能和乐趣,那么它实际上来自Erlang VM内部的工作方式吗?

拥有两种类型的函数并从一种类型转换为另一种类型以便将它们传递给其他函数有什么好处吗?使用两种不同的符号来调用函数有好处吗?

最佳答案

为了澄清命名,它们都是函数。一个是命名函数,另一个是匿名函数。但你是对的,它们的工作方式有些不同,我将说明它们为什么这样工作。

让我们从第二个fn开始。 fn 是一个闭包,类似于 Ruby 中的 lambda。我们可以按如下方式创建它:

x = 1
fun = fn y -> x + y end
fun.(2) #=> 3

一个函数也可以有多个子句:

x = 1
fun = fn
y when y < 0 -> x - y
y -> x + y
end
fun.(2) #=> 3
fun.(-2) #=> 3

现在,让我们尝试一些不同的东西。让我们尝试定义需要不同数量参数的不同子句:

fn
x, y -> x + y
x -> x
end
** (SyntaxError) cannot mix clauses with different arities in function definition

哦不!我们得到一个错误!我们不能混合需要不同数量参数的子句。函数始终具有固定的数量。

现在,我们来谈谈命名函数:

def hello(x, y) do
x + y
end

正如预期的那样,它们有一个名称,并且还可以接收一些参数。然而,它们不是闭包:

x = 1
def hello(y) do
x + y
end

此代码将无法编译,因为每次看到 def 时,您都会得到一个空的变量范围。这是它们之间的一个重要区别。我特别喜欢这样一个事实:每个命名函数都从一个干净的石板开始,并且您不会将不同作用域的变量全部混合在一起。你有一个清晰的界限。

我们可以将上面的命名 hello 函数作为匿名函数检索。您自己提到过:

other_function(&hello(&1))

然后你问,为什么我不能像其他语言那样简单地将其传递为 hello ?这是因为 Elixir 中的函数是通过名称数量来标识的。因此,需要两个参数的函数与需要三个参数的函数是不同的,即使它们具有相同的名称。因此,如果我们只是传递 hello,我们将不知道您真正的意思是哪个 hello。有两个、三个或四个参数的那个?这与我们无法创建具有不同参数的子句的匿名函数的原因完全相同。

从 Elixir v0.10.1 开始,我们有一种捕获命名函数的语法:

&hello/1

这将捕获具有 arity 1 的本地命名函数 hello。在整个语言及其文档中,使用此 hello/1 语法来识别函数是很常见的。

这也是 Elixir 使用点来调用匿名函数的原因。由于您不能简单地将 hello 作为函数传递,而是需要显式捕获它,因此命名函数和匿名函数之间存在自然区别,并且调用每个函数的不同语法使一切变得更加复杂显式(由于 Lisp 1 与 Lisp 2 的讨论,Lispers 会熟悉这一点)。

总的来说,这就是我们有两个函数以及它们表现不同的原因。

关于erlang - Elixir 中为什么有两种函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18011784/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com