English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Рекурсия является важной частью Erlang. Давайте сначала посмотрим, как можно реализовать простую рекурсию через программу factorial.
-module(helloworld). -export([fac/1, start/0]). fac(N) when N == 0 -> 1; fac(N) when N > 0 -> N * fac(N-1). start() -> X = fac(4), io:fwrite("~w",[X]).
Обратим внимание на以下几点 в отношении вышеуказанного программы:
Сначала мы определяем функцию fac(N).
Мы можем определить рекурсивную функцию fac(N) через рекурсивный вызов fac(N).
Вывод программы:
24
В этой главе мы рассмотрим различные типы рекурсии и их использование в Erlang.
Одна из более实用的 методов рекурсии можно увидеть из простого примера определения длины списка. Список может иметь несколько значений, например, [1,2,3,4]. Давайте используем рекурсию, чтобы понять, как получить длину списка.
-module(helloworld). -export([len/1, start/0]). len([]) -> 0; len([_|T]) -> 1 + len(T). start() -> X = [1,2,3,4], Y = len(X), io:fwrite("~w",[Y]).
Обратим внимание на以下几点 в отношении вышеуказанного программы:
Если список пуст, то первая функция len([]) используется для特殊情况.
[H|T] шаблон для соответствия списку с одним или несколькими элементами, например, список длиной 1 будет определен как [X|[]], а список длиной 2 будет определен как [X|[Y|[]]].
Обратите внимание, что вторым элементом является список сам по себе. Это означает, что нам нужно только посчитать первый, функция может вызывать себя на втором элементе. В списке каждый элемент имеет длину 1.
Вывод программы на上面
4
Чтобы понять, как работает тailed рекурсия, давайте рассмотрим, как работает следующий код в предыдущем разделе.
Грамматика
len([]) -> 0; len([_|T]) -> 1 + len(T).
Ответ на 1 + len (Rest) нужно найти, сначала найдя ответ на len (Rest). Затем функция len (Rest) сама должна найти результат другого вызова функции. Часть добавления будет堆积иваться, пока не будет найден последний, после чего можно будет вычислить конечный результат.
Тailed рекурсия предназначена для устранения этого наложения операций, уменьшая их при выполнении операции.
Чтобы это реализовать, нам нужно сохранить дополнительную временную переменную в функции в качестве параметра. Упомянутая ранее временная переменная иногда называется накопителем и используется для хранения места для хранения результатов вычислений, чтобы ограничить рост вызовов.
Давайте看一下 пример тailed рекурсии
-module(helloworld). -export([tail_len/1,tail_len/2,start/0]). tail_len(L) -> tail_len(L,0). tail_len([], Acc) -> Acc; tail_len([_|T], Acc) -> tail_len(T,Acc+1). start() -> X = [1,2,3,4], Y = tail_len(X), io:fwrite("~w",[Y]).
Вывод программы на上面
4
Давайте рассмотрим пример рекурсии. В этот раз давайте напишем функцию, которая принимает целое число в качестве первого параметра и любое другое значение в качестве второго параметра. Затем она создаст список, содержащий копии термина, указанного целым числом.
Давайте看一下 такой пример-
-module(helloworld). -export([duplicate/2,start/0]). duplicate(0,_) -> []; duplicate(N,Term) when N > 0 -> io:fwrite("~w,~n",[Term]), [Term|duplicate(N-1,Term)]. start() -> duplicate(5,1).
Вывод программы выше будет -
1, 1, 1, 1, 1,
В Erlang можно использовать рекурсию без ограничений. Давайте быстро посмотрим, как использовать рекурсию для инверсии элементов списка. Для выполнения этой операции можно использовать следующий программный код.
-module(helloworld). -export([tail_reverse/2,start/0]). tail_reverse(L) -> tail_reverse(L,[]). tail_reverse([],Acc) -> Acc; tail_reverse([H|T],Acc) -> tail_reverse(T, [H|Acc]). start() -> X = [1,2,3,4], Y = tail_reverse(X), io:fwrite("~w",[Y]).
Вывод программы выше будет -
[4,3,2,1]
Обратим внимание на以下几点 в отношении вышеуказанного программы:
Мы снова используем концепцию временной переменной, чтобы хранить каждый элемент списка в переменной с именем Acc.
Затем рекурсивно вызываем tail_reverse, но на этот раз мы уверены, что последний элемент сначала помещается в новый список.
Затем рекурсивно вызываем tail_reverse для каждого элемента списка.