Понимание вызова функций и сопоставления с образцом

Прошел месяц с тех пор, как я начал изучать программирование на Эликсире, сегодня мне удалось написать код для получения последовательности Фибоначчи самостоятельно, без обращения к какой-либо документации или помощи моего учителя.

И это заняло всего 2 часа ;)

Позвольте мне провести вас через путешествие.

|› Последовательность Фибоначчи

Таким образом, последовательность Фибоначчи начинается с 0,1, а следующее число в последовательности является суммой двух предыдущих чисел. Образец «0,1,1,2,3,5,8,…»

|› Определение функций и элементов

Чтобы начать последовательность, мне нужно как минимум два целых числа, поэтому я начал со следующего.

defmodule Fibonacci do
 def fib(n) do
  fib(0, 1, [], n)
 end
end

Здесь я определил функцию «fib(n)» ​​с одной арностью «n», которая является входным значением от пользователя, что означает, что программа должна возвращать первое число «n» значений в последовательности Фибоначчи. Это также количество раз, которое должна произойти рекурсия для получения желаемого результата.

В теле вышеуказанной функции я назвал другую функцию «fib(0, 1, [], n)», которая еще не существует, и эта функция имеет 4 арности, и эта функция отличается от той, которую я определил ранее.

|› Сопоставление шаблонов и рекурсия

Теперь я определяю функцию «fib(prev, curr, acc, n)», которая также имеет 4 арности. когда я вызываю эту функцию в строке 3, значения в «fib(0, 1, [], n)» соответствуют образцу функции в строке 6, и эти значения будут скомпилированы в теле функции.

Здесь я также принимаю входное значение от пользователя «n = 5», полученное из функции в строке 2 «fib (n)».

defmodule Fibonacci do
 def fib(n) do
   fib(0, 1, [], n)
 end
 def fib(prev, curr, acc, n) do
   fib(curr, prev + curr, [curr | acc], n - 1)
 end
end

Итак, строка 6 'fib(prev, curr, acc, n)' берет значения из строки 3 'fib(0, 1, [], 5)' и вводит эти значения в строку 7 'fib(curr, prev + curr, [curr | acc], n — 1)», которое станет «fib(1, 1+1, [ 1,[1]], 5–1)». Это когда рекурсия начинается, когда я вызываю функцию в теле той же функции, что означает, что она вызывает ту же функцию с новыми значениями и продолжает добавлять последовательность Фибоначчи к «acc». вот что происходит в строке 7

fib(1, 1+1, [ 1,[1] ], 5–1) → fib(1, 2, [ 1,[1] ], 4)

fib(2, 1+2, [ 2,[1,1] ], 4–1) → fib(2, 3, [ 2,[1,1] ], 3)

fib(3, 2+3, [ 3,[2,1,1] ], 3–1) → fib(3, 5, [ 3,[2,1,1] ], 2)

fib(5, 3+5, [ 5,[3,2,1,1] ], 2–1) -> fib(5, 8, [ 3,[2,1,1] ], 1)

fib(8, 5+8, [ 8,[5,3,2,1,1] ], 1–1) → fib(8, 13, [ 5,[3,2,1,1] ], 0)

Теперь значение «n» стало равным нулю, и мне нужно написать случай/функцию, что происходит, когда «n = 0», что, очевидно, возвращает последовательность в «acc», которая равна «[5,3,2,1,1] '

|› Возврат выхода из аккумулятора

строка 6 — это новая функция с 4 ариями, которая должна соответствовать шаблону с нашей предыдущей функцией, и она должна быть написана перед предыдущей функцией, чтобы компиляция вернула «acc», что «n = 0». я отключил первые два символа подчеркивания, так как они не требуются в этой функции.

defmodule Fibonacci do
 def fib(n) do
   fib(0, 1, [], n)
 end
 def fib(_prev, _curr, acc, 0) do
   acc
 end
 def fib(prev, curr, acc, n) do
 fib(curr, prev + curr, [curr | acc], n - 1)
 end
end

Когда вы компилируете код, он возвращает следующее.

Как вы заметили, здесь отсутствует ноль, а также возвращаются значения в обратном порядке. ну это легко исправить.

|› перечисление

defmodule Fibonacci do
 def fib(n) do
   fib(0, 1, [], n)
 end
 def fib(_prev, _curr, acc, 0) do
   acc |> Enum.reverse()
 end
 def fib(prev, curr, acc, n) do
   fib(curr, prev + curr, [curr | acc], n - 1)
 end
end

Добавьте ‘|› Enum.reverse()’ в строку 7 после ‘acc’, это меняет порядок списка в ‘acc’ и возвращает список, как показано ниже.

|› Изменение входных значений

Теперь для нуля я ввожу «[0]» в «acc» вместо пустого списка «[]», и это вернет 6 значений вместо 5 в последовательности, поэтому я также вычитаю «1» из «n».

defmodule Fibonacci do
 def fib(n) do
   fib(0, 1, [0], n - 1)
 end
 def fib(_prev, _curr, acc, 0) do
   acc |> Enum.reverse()
 end
 def fib(prev, curr, acc, n) do
   fib(curr, prev + curr, [curr | acc], n - 1)
 end
end

После изменения строки 3, ниже возврат.

|› Отказоустойчивый

Я пошел немного дальше, чтобы защитить код от попадания в цикл, если пользователь вводит ноль, используя «если еще».

defmodule Fibonacci do
 def fib(n) do
   if n > 0 do
     fib(0, 1, [0], n - 1)
   else
     "Please enter a value greater than zero"
   end
 end
 def fib(_prev, _curr, acc, 0) do
   acc |> Enum.reverse()
 end
 def fib(prev, curr, acc, n) do
   fib(curr, prev + curr, [curr | acc], n - 1)
 end
end

Возвращает

Финито.. Увидимся позже на другом |›