在erlang中进行增量的步骤是什么?

时间:2016-12-08 02:58:19

标签: erlang increment

increment([]) -> [];
increment([H|T]) -> [H+1|increment(T)].

decrement([]) -> [];
decrement([H|T]) -> [H-1|decrement(T)].

所以我有这个代码,但我不知道它们如何在java中正常工作。

1 个答案:

答案 0 :(得分:1)

Java和Erlang是不同的野兽。我不建议在学习Erlang时尝试与Java进行比较,特别是如果Java是迄今为止你所知道的唯一语言。您发布的代码是称为“函数式编程”的范例的一个很好的例子。我建议你阅读一下这个主题,以帮助你了解正在发生的事情。为了尝试在Erlang中解决这个问题,你需要了解Erlang函数与Java方法完全不同。

在Java中,方法签名由方法名称及其参数类型组成。返回类型也很重要。像您编写的函数一样的Java increment方法可能像List<Integer> increment(List<Integer> input)那样编写。 Java方法的主体可能会一次遍历列表中的一个元素,并将每个元素设置为自身加一个:

List<Integer> increment(List<Integer> input) {
    for (int i = 0; i < input.size; i++) {
        input.set(i, input.get(i) + 1);
    }
}

Erlang与此几乎没有任何共同之处。首先,erlang函数的“签名”是函数的名称和元素。 Arity表示函数接受多少个参数。因此,您的增量函数称为increment/1,这是它的唯一签名。在函数名称之后在括号中写入参数列表的方式与参数类型的关系比与传递给它的数据模式的关系更少。像increment([]) -> ...这样的函数只能通过传递空[]来成功调用。同样,函数increment([Item]) -> ...只能通过向其传递一个包含一个项目的列表来成功调用,并且increment([Item1, Item2]) -> ...必须传递一个包含两个项目的列表。这种将数据与模式匹配的概念非常恰当地称为“模式匹配”,您可以在许多函数式语言中找到它。在Erlang函数中,它用于选择要执行的函数头。这与Java的方法重载大致相似,在这里您可以使用多个具有相同名称但不同参数类型的方法;但是,Erlang函数头中的模式可以将变量绑定到与模式匹配的不同参数部分。

在您的代码示例中,函数increment/1有两个头。仅当您将空列表传递给函数时,才会执行第一个头。仅当您将非空列表传递给函数时,才会执行第二个头。发生这种情况时,绑定了两个变量HTH绑定到列表的第一项,T绑定到列表的其余部分,这意味着除了第一项之外的所有项目。这是因为模式[H|T]匹配非空列表,包括具有一个元素的列表,在这种情况下T将绑定到空列表。这样绑定的变量可以用在函数体中。

函数体是在Erlang中迭代列表以生成新列表的一种非常典型的形式。这是典型的,因为与Java的另一个重要区别是,Erlang数据是不可变的。这意味着没有像我在上面的Java代码中那样设置“设置列表元素”这样的概念。如果要更改列表,则必须构建一个新列表,这是您的代码所做的。它有效地说:

  • 增加空列表的结果是空列表。
  • 递增非空列表的结果是:
    • 获取列表的第一个元素:H
    • 增加列表的其余部分:increment(T)
    • H+1添加到递增列表其余部分的结果中。

请注意,您要小心如何在Erlang中构建列表,否则最终会浪费大量资源。 List Handling User's Guide是了解这一点的好地方。另请注意,此代码使用称为“递归”的概念,这意味着函数会调用自身。在许多流行语言(包括Java)中,递归的用处有限,因为每个新函数调用都会添加堆栈帧,而堆栈帧的可用内存空间相对有限。 Erlang和许多函数式语言支持称为“尾部调用消除”的东西,这是一种允许正确编写的代码无限期地递归而不会耗尽任何资源的功能。

希望这有助于解释事情。如果您可以提出更具体的问题,您可能会得到更好的答案。