Skip to content

Commit 08e665f

Browse files
committed
Added demos for functional recursion
1 parent a1b3635 commit 08e665f

14 files changed

+337
-0
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ Todas as contribuições são bem-vindas.
9898
- [Demo](https://github.com/NelsonBN/algorithms-data-structures-recursion)
9999
- Paradigma Funcional
100100
- [Youtube - Encontro](https://www.youtube.com/watch?v=rbEYjJdaIZI)
101+
- [Demo](./src/functional-recursion/README.md)
101102

102103

103104
- [x] **Queue**
+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Used by "mix format"
2+
[
3+
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
4+
]

src/functional-recursion/.gitignore

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# The directory Mix will write compiled artifacts to.
2+
/_build/
3+
4+
# If you run "mix test --cover", coverage assets end up here.
5+
/cover/
6+
7+
# The directory Mix downloads your dependencies sources to.
8+
/deps/
9+
10+
# Where third-party dependencies like ExDoc output generated docs.
11+
/doc/
12+
13+
# Ignore .fetch files in case you like to edit your project deps locally.
14+
/.fetch
15+
16+
# If the VM crashes, it generates a dump, let's ignore it too.
17+
erl_crash.dump
18+
19+
# Also ignore archive artifacts (built via "mix archive.build").
20+
*.ez
21+
22+
# Ignore package tarball (built via "mix hex.build").
23+
fibonacci-*.tar
24+
25+
# Temporary files, for example, from tests.
26+
/tmp/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{
8+
"type": "mix_task",
9+
"name": "mix (Default task)",
10+
"request": "launch",
11+
"projectDir": "${workspaceRoot}"
12+
},
13+
{
14+
"type": "mix_task",
15+
"name": "mix test",
16+
"request": "launch",
17+
"task": "test",
18+
"taskArgs": [
19+
"--trace"
20+
],
21+
"startApps": true,
22+
"projectDir": "${workspaceRoot}",
23+
"requireFiles": [
24+
"test/**/test_helper.exs",
25+
"test/**/*_test.exs"
26+
]
27+
}
28+
]
29+
}

src/functional-recursion/README.md

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Fibonacci
2+
3+
**TODO: Add description**
4+
5+
## Installation
6+
7+
1. **Download and install Erlang:**
8+
9+
Go to the [Erlang Downloads page](https://www.erlang.org/downloads) and download the installer for Windows. Run the installer and follow the on-screen instructions.
10+
11+
2. **Download and install Elixir:**
12+
13+
Go to the [Elixir Downloads page](https://elixir-lang.org/install.html#windows) and download the installer for Windows. Run the installer and follow the on-screen instructions.
14+
15+
## Running the Project
16+
17+
1. **Install dependencies:**
18+
19+
```bash
20+
mix deps.get
21+
```
22+
23+
2. **Run the tests:**
24+
25+
```bash
26+
mix test
27+
```
28+
29+
Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
30+
and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
31+
be found at <https://hexdocs.pm/fibonacci>.
32+
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
defmodule Fibonacci do
2+
@moduledoc """
3+
Documentation for `Fibonacci`.
4+
"""
5+
6+
def fib(0), do: 0
7+
def fib(1), do: 1
8+
def fib(n), do: fib(n - 1) + fib(n - 2)
9+
10+
def fib_tco(n), do: do_fib(n, 0, 1)
11+
defp do_fib(0, a, _), do: a
12+
defp do_fib(1, _, b), do: b
13+
defp do_fib(n, a, b), do: do_fib(n - 1, b, a + b)
14+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
defmodule MathOperations do
2+
def print([]) do
3+
IO.puts("Fim da lista")
4+
end
5+
6+
def print(list) do
7+
head = hd(list)
8+
tail = tl(list)
9+
10+
IO.puts(head)
11+
print(tail)
12+
end
13+
14+
def sum_numbers([]) do
15+
0
16+
end
17+
18+
def sum_numbers(numbers) do
19+
[head | tail] = numbers
20+
21+
head + sum_numbers(tail)
22+
end
23+
24+
def sum_numbers_tr([], sum) do
25+
sum
26+
end
27+
28+
def sum_numbers_tr(numbers, sum) do
29+
[head | tail] = numbers
30+
31+
temp_sum = head + sum
32+
sum_numbers_tr(tail, temp_sum)
33+
end
34+
35+
def double([]) do
36+
[]
37+
end
38+
39+
def double([head | tail]) do
40+
[head * 2 | double(tail)]
41+
end
42+
43+
def double_tr(list, list \\ [])
44+
def double_tr([], list), do: Enum.reverse(list)
45+
46+
def double_tr(numbers, list) do
47+
head = hd(numbers)
48+
tail = tl(numbers)
49+
50+
double = head * 2
51+
52+
double_tr(tail, [double | list])
53+
end
54+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
defmodule Parentheses do
2+
def is_parentheses_valid?(text) do
3+
validate_recursive(String.graphemes(text), [])
4+
end
5+
6+
defp validate_recursive([], []), do: true
7+
8+
defp validate_recursive([], _stack), do: false
9+
10+
defp validate_recursive(["(" | tail], stack) do
11+
validate_recursive(tail, [")" | stack])
12+
end
13+
14+
defp validate_recursive([")" | tail], [")" | tail_stack]),
15+
do: validate_recursive(tail, tail_stack)
16+
17+
defp validate_recursive([_ | tail], stack) do
18+
validate_recursive(tail, stack)
19+
end
20+
21+
def is_parentheses_valid_iterative?(text) do
22+
count =
23+
text
24+
|> String.graphemes()
25+
|> Enum.reduce(0, fn char, count ->
26+
case char do
27+
"(" -> count + 1
28+
")" -> count - 1
29+
_ -> count
30+
end
31+
end)
32+
33+
count == 0
34+
end
35+
end

src/functional-recursion/mix.exs

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
defmodule Fibonacci.MixProject do
2+
use Mix.Project
3+
4+
def project do
5+
[
6+
app: :fibonacci,
7+
version: "0.1.0",
8+
elixir: "~> 1.16",
9+
start_permanent: Mix.env() == :prod,
10+
deps: deps()
11+
]
12+
end
13+
14+
# Run "mix help compile.app" to learn about applications.
15+
def application do
16+
[
17+
extra_applications: [:logger]
18+
]
19+
end
20+
21+
# Run "mix help deps" to learn about dependencies.
22+
defp deps do
23+
[
24+
{:benchee, "~> 1.3"},
25+
{:dialyxir, "~> 1.4", only: [:dev, :test], runtime: false},
26+
# {:dep_from_hexpm, "~> 0.3.0"},
27+
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
28+
]
29+
end
30+
end

src/functional-recursion/mix.lock

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
%{
2+
"benchee": {:hex, :benchee, "1.3.0", "f64e3b64ad3563fa9838146ddefb2d2f94cf5b473bdfd63f5ca4d0657bf96694", [:mix], [{:deep_merge, "~> 1.0", [hex: :deep_merge, repo: "hexpm", optional: false]}, {:statistex, "~> 1.0", [hex: :statistex, repo: "hexpm", optional: false]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "34f4294068c11b2bd2ebf2c59aac9c7da26ffa0068afdf3419f1b176e16c5f81"},
3+
"deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"},
4+
"dialyxir": {:hex, :dialyxir, "1.4.3", "edd0124f358f0b9e95bfe53a9fcf806d615d8f838e2202a9f430d59566b6b53b", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "bf2cfb75cd5c5006bec30141b131663299c661a864ec7fbbc72dfa557487a986"},
5+
"erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
6+
"statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"},
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
defmodule FibonacciTest do
2+
use ExUnit.Case
3+
doctest Fibonacci
4+
5+
test "fibonacci" do
6+
assert Fibonacci.fib(2) == 1
7+
assert Fibonacci.fib(6) == 8
8+
assert Fibonacci.fib(10) == 55
9+
end
10+
11+
test "fibonacci tail call optimization" do
12+
assert Fibonacci.fib_tco(2) == 1
13+
assert Fibonacci.fib_tco(6) == 8
14+
assert Fibonacci.fib_tco(10) == 55
15+
end
16+
17+
test "Benchmark" do
18+
n = 20
19+
20+
Benchee.run(
21+
%{
22+
"fibonacci" => fn -> Fibonacci.fib(n) end,
23+
"fibonacci with tail-call optimization" => fn -> Fibonacci.fib_tco(n) end
24+
},
25+
print: [fast_warning: false])
26+
end
27+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
defmodule RecursionTest do
2+
use ExUnit.Case
3+
4+
test "sum_numbers" do
5+
assert MathOperations.sum_numbers([1, 2, 3, 4]) == 10
6+
assert MathOperations.sum_numbers_tr([1, 2, 3, 4], 0) == 10
7+
end
8+
9+
test "Sum numbers benchmark" do
10+
array = 0..1000 |> Enum.to_list()
11+
12+
Benchee.run(
13+
%{
14+
"Body recursive" => fn -> MathOperations.sum_numbers(array) end,
15+
"Tail recursive" => fn -> MathOperations.sum_numbers_tr(array, 0) end
16+
},
17+
print: [fast_warning: false]
18+
)
19+
end
20+
21+
test "Double numbers in array" do
22+
assert MathOperations.double([1, 2, 3, 4]) == [2, 4, 6, 8]
23+
assert MathOperations.double_tr([1, 2, 3, 4]) == [2, 4, 6, 8]
24+
end
25+
26+
@tag skip: true
27+
test "Double numbers benchmark" do
28+
array = 0..1000 |> Enum.to_list()
29+
30+
Benchee.run(
31+
%{
32+
"Body recursive" => fn -> MathOperations.double(array) end,
33+
"Tail recursive" => fn -> MathOperations.double_tr(array) end
34+
},
35+
print: [fast_warning: false]
36+
)
37+
end
38+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
defmodule ParenthesesTest do
2+
use ExUnit.Case
3+
4+
test "Validate parentheses recursive" do
5+
assert Parentheses.is_parentheses_valid?("(text)") == true
6+
assert Parentheses.is_parentheses_valid?("((text))") == true
7+
assert Parentheses.is_parentheses_valid?("()()") == true
8+
assert Parentheses.is_parentheses_valid?("(text") == false
9+
assert Parentheses.is_parentheses_valid?("(text)(") == false
10+
assert Parentheses.is_parentheses_valid?("((text") == false
11+
end
12+
13+
test "Validate parentheses iterative" do
14+
assert Parentheses.is_parentheses_valid_iterative?("(text)") == true
15+
assert Parentheses.is_parentheses_valid_iterative?("((text))") == true
16+
assert Parentheses.is_parentheses_valid_iterative?("()()") == true
17+
assert Parentheses.is_parentheses_valid_iterative?("(text") == false
18+
assert Parentheses.is_parentheses_valid_iterative?("(text)(") == false
19+
assert Parentheses.is_parentheses_valid_iterative?("((text") == false
20+
end
21+
22+
@tag skip: true
23+
test "Validate parentheses benchmark" do
24+
inputs = %{
25+
"case single pair valid" => "(text)",
26+
"case double pair valid" => "((text))",
27+
"case long text valid" => "(fdsfsfddsfsdfsdfsfsdfddsdfddddsdfsfsdfsdfsdfsdfsdfdsf)",
28+
"case long text invalid" => "fdsdfsfddsfsdfsdfsfsdfddsdfddddsdfsfsdfsdfsdfsdfsdfdsf)"
29+
}
30+
31+
Benchee.run(
32+
%{
33+
"Recursive" => fn input -> Parentheses.is_parentheses_valid?(input) end,
34+
"Iterative" => fn input -> Parentheses.is_parentheses_valid_iterative?(input) end
35+
},
36+
inputs: inputs,
37+
print: [fast_warning: false])
38+
end
39+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ExUnit.start()

0 commit comments

Comments
 (0)