为什么Elixir有两种功能? [英] Why are there two kinds of functions in Elixir?

查看:116
本文介绍了为什么Elixir有两种功能?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm learning Elixir and wonder why it has two types of function definitions:


  • 在$ $ c的模块中定义的函数$ c> def ,使用 myfunction(param1,param2)

  • 使用 fn ,使用 myfn。(param1,param2)

  • functions defined in a module with def, called using myfunction(param1, param2)
  • anonymous functions defined with fn, called using myfn.(param1, param2)

只有第二种函数似乎是第一类对象,可以作为参数传递给其他函数。一个模块中定义的函数需要包装在一个 fn 中。有一些句法糖看起来像 otherfunction(myfunction(& 1,& 2)),以便使这很容易,但为什么首先需要它?为什么我们不能做 otherfunction(myfunction))?是否只允许在Ruby中调用没有括号的模块函数?它似乎已经继承了Erlang的这个特性,它也具有模块功能和乐趣,它实际上来自于Erlang VM在内部工作的方式吗?

Only the second kind of function seems to be a first-class object and can be passed as a parameter to other functions. A function defined in a module needs to be wrapped in a fn. There's some syntactic sugar which looks like otherfunction(myfunction(&1, &2)) in order to make that easy, but why is it necessary in the first place? Why can't we just do otherfunction(myfunction))? Is it only to allow calling module functions without parenthesis like in Ruby? It seems to have inherited this characteristic from Erlang which also has module functions and funs, so does it actually comes from how the Erlang VM works internally?

两种类型的功能,并从一种类型转换为另一类,以便将它们传递给其他功能?是否有两个不同符号调用函数的好处?

It there any benefit having two types of functions and converting from one type to another in order to pass them to other functions? Is there a benefit having two different notations to call functions?

推荐答案

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

Just to clarify the naming, they are both functions. One is a named function and the other is an anonymous one. But you are right, they work somewhat differently and I am going to illustrate why they work like that.

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

Let's start with the second, fn. fn is a closure, similar to a lambda in Ruby. We can create it as follows:

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

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

A function can have multiple clauses too:

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

现在,让我们尝试不同的东西。我们尝试定义不同的条款,期望不同数量的参数:

Now, let's try something different. Let's try to define different clauses expecting a different number of arguments:

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

哦不,我们收到错误!我们不能混合期望不同数量参数的子句。一个函数总是有固定的。

Oh no! We get an error! We cannot mix clauses that expects a different number of arguments. A function always has a fixed arity.

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

Now, let's talk about the named functions:

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

如预期的,他们有一个名字,他们也可以收到一些参数。但是,它们不是闭包:

As expected, they have a name and they can also receive some arguments. However, they are not closures:

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

此代码无法编译,因为每次看到 def ,你会得到一个空的变量范围。这是他们之间的一个重要区别。我特别喜欢每个命名的函数都是以一个干净的格式开始的,你不会把不同范围的变量全部混在一起。你有一个清晰的边界。

This code will fail to compile because every time you see a def, you get an empty variable scope. That is an important difference between them. I particularly like the fact each named function starts with a clean slate and you don't get the variables of different scopes all mixed up together. You have a clear boundary.

我们可以将匿名函数的命名为hello函数。你自己提到过:

We could retrieve the named hello function above as an anonymous function. You mentioned about it yourself:

other_function(&hello(&1))

然后你问,为什么我不能像其他语言一样将它作为 hello 传递?这是因为Elixir中的功能由名称来标识。所以一个期望两个参数的函数是一个不同于预期有三个参数的函数,即使它们具有相同的名称。所以如果我们简单地通过 hello ,那么我们不知道你实际上是指哪个 hello 那两个,三个还是四个论点的一个?这是完全一样的原因,为什么我们不能创建一个具有不同优点的子句的匿名函数。

And then you asked, why I cannot simply pass it as hello as in other languages? That's because functions in Elixir are identified by name and arity. So a function that expects two arguments is a different function than one that expects three, even if they had the same name. So if we simply passed hello, we would have no idea which hello you actually meant. The one with two, three or four arguments? This is exactly the same reason why we can't create an anonymous function with clauses with different arities.

由于Elixir v0.10.1,我们有一个语法来捕获命名函数:

Since Elixir v0.10.1, we have a syntax to capture named functions:

&hello/1

这将捕获本地命名函数hello与arity 1.在整个语言及其文档中,在 hello / 1 语法

That will capture the local named function hello with arity 1. Throughout the language and its documentation, it is very common to identify functions in this hello/1 syntax.

这也是为什么Elixir使用一个点来调用匿名函数的原因。因为你不能简单地通过 hello 作为一个函数,而是需要明确地捕获它,命名和匿名函数之间有一个自然的区别和一个不同的调用语法每个都使一切都更加明确(Lispers会熟悉这一点,因为Lisp 1和Lisp 2讨论)。

This is also why Elixir uses a dot for calling anonymous functions. Since you can't simply pass hello around as a function, instead you need to explicitly capture it, there is a natural distinction between named and anonymous functions and a distinct syntax for calling each makes everything a bit more explicit (Lispers would be familiar with this due to the Lisp 1 vs. Lisp 2 discussion).

总的来说,这些是我们有两个功能,以及为什么他们的行为不同。

Overall, those are the reasons why we have two functions and why they behave differently.

这篇关于为什么Elixir有两种功能?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆