- Mastering Elixir
- André Albuquerque Daniel Caixinha
- 624字
- 2021-08-05 10:42:48
Looping through recursion
We'll show you how to create a recursive functions through two simple examples: doubling each element on a list, and multiplying consecutive elements of a list. As mentioned earlier, although you probably won't be using this in your day-to-day coding, it's still very important to understand how this work. This way, if the abstractions Elixir provides aren't enough for your use case, you can just create your own recursive functions to accomplish what you need.
Before jumping into the examples, let's explain generally how recursive functions work. In Elixir, they're usually implemented as a multi-clause function, using pattern matching to control its flow of execution. The first clause sets the condition that will stop the recursion, and is followed by other broader clauses that apply the recursion.
In the first example, we want to take a list of integers as input, and return a new list where each element is multiplied by two. Let's see the code for such a function:
$ cat examples/double.ex
defmodule Recursion do
def double([]), do: []
def double([head | tail]) do
[head * 2 | double(tail)]
end
end
Here are its results:
iex> Recursion.double([2, 4, 6])
[4, 8, 12]
Besides using multi-clause functions, we're also using pattern matching in two ways: to know when we've reached the end (and the empty list) and treat it accordingly; and to extract the head and the tail of a list, similar to what we've shown in the pattern matching section. The recursion happens when we call double(tail). As we're only passing the tail to the recursive call, we're essentially iterating through the list. When we reach an empty list, the first clause matches, we return an empty list, and all of the intermediate calls will unfold and create our new list.
What if, instead of returning a new list, we want to return a single value? We'll exemplify this by multiplying consecutive elements of a list. Here's the code to do it:
$ cat examples/multiply.ex
defmodule Recursion do
def multiply([]), do: 1
def multiply([head | tail]) do
head * multiply(tail)
end
end
Here's its use on an IEx session:
iex> Recursion.multiply([1, 2, 3])
6
The strategy is similar to the one shown in the previous example, except, instead of adding an element to a list at each step, we're now using our head as an accumulator. Also, it's important to note that, since we're doing a multiplication, our stopping condition must return 1 (the neutral element of this operation). The definition of the stopping condition varies between different problems, and is, arguably, one of the most important steps of defining a function recursively.
A common concern when dealing with recursive functions is its memory usage, as we have multiple function calls that will get into the stack. The Erlang runtime employs tail-call optimization whenever it can, which means that a recursive call won't generate a new stack push. For the runtime to do this optimization, you have to ensure that the last thing our function does is call another function (including itself)–or, in other words, make a tail call. Here's our multiply function updated to make tail calls:
$ cat examples/multiply_with_tail_recursion.ex
def multiply(list, accum \\ 1)
def multiply([], accum), do: accum
def multiply([head | tail], accum) do
multiply(tail, head * accum)
end
The usual strategy is to pass an accumulator around, which enables us to use the tail-call optimization. Note that there's a trade-off here: On one hand, this optimization is important when dealing with large collections (since function calls don't consume additional memory); on the other hand, code that doesn't use this optimization is usually easier to read and comprehend, as it's usually more concise. When doing recursion, consider the advantages and disadvantages of each solution.
- Delphi程序設計基礎:教程、實驗、習題
- Python自動化運維快速入門
- Web交互界面設計與制作(微課版)
- Selenium Design Patterns and Best Practices
- 三維圖形化C++趣味編程
- Mastering Apache Maven 3
- Kotlin從基礎到實戰
- Java系統化項目開發教程
- 零基礎學HTML+CSS第2版
- Instant Automapper
- SEO教程:搜索引擎優化入門與進階(第3版)
- Learning Unreal Engine Game Development
- DB2SQL性能調優秘笈
- jQuery基礎教程(第4版)
- Modular Programming with PHP 7