Skip to content

Commit

Permalink
Added demos for functional recursion
Browse files Browse the repository at this point in the history
  • Loading branch information
NelsonBN committed Jun 19, 2024
1 parent a1b3635 commit 08e665f
Show file tree
Hide file tree
Showing 14 changed files with 337 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ Todas as contribuições são bem-vindas.
- [Demo](https://github.com/NelsonBN/algorithms-data-structures-recursion)
- Paradigma Funcional
- [Youtube - Encontro](https://www.youtube.com/watch?v=rbEYjJdaIZI)
- [Demo](./src/functional-recursion/README.md)


- [x] **Queue**
Expand Down
4 changes: 4 additions & 0 deletions src/functional-recursion/.formatter.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Used by "mix format"
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]
26 changes: 26 additions & 0 deletions src/functional-recursion/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# The directory Mix will write compiled artifacts to.
/_build/

# If you run "mix test --cover", coverage assets end up here.
/cover/

# The directory Mix downloads your dependencies sources to.
/deps/

# Where third-party dependencies like ExDoc output generated docs.
/doc/

# Ignore .fetch files in case you like to edit your project deps locally.
/.fetch

# If the VM crashes, it generates a dump, let's ignore it too.
erl_crash.dump

# Also ignore archive artifacts (built via "mix archive.build").
*.ez

# Ignore package tarball (built via "mix hex.build").
fibonacci-*.tar

# Temporary files, for example, from tests.
/tmp/
29 changes: 29 additions & 0 deletions src/functional-recursion/.vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "mix_task",
"name": "mix (Default task)",
"request": "launch",
"projectDir": "${workspaceRoot}"
},
{
"type": "mix_task",
"name": "mix test",
"request": "launch",
"task": "test",
"taskArgs": [
"--trace"
],
"startApps": true,
"projectDir": "${workspaceRoot}",
"requireFiles": [
"test/**/test_helper.exs",
"test/**/*_test.exs"
]
}
]
}
32 changes: 32 additions & 0 deletions src/functional-recursion/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Fibonacci

**TODO: Add description**

## Installation

1. **Download and install Erlang:**

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.

2. **Download and install Elixir:**

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.

## Running the Project

1. **Install dependencies:**

```bash
mix deps.get
```

2. **Run the tests:**

```bash
mix test
```

Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
be found at <https://hexdocs.pm/fibonacci>.

14 changes: 14 additions & 0 deletions src/functional-recursion/lib/fibonacci.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
defmodule Fibonacci do
@moduledoc """
Documentation for `Fibonacci`.
"""

def fib(0), do: 0
def fib(1), do: 1
def fib(n), do: fib(n - 1) + fib(n - 2)

def fib_tco(n), do: do_fib(n, 0, 1)
defp do_fib(0, a, _), do: a
defp do_fib(1, _, b), do: b
defp do_fib(n, a, b), do: do_fib(n - 1, b, a + b)
end
54 changes: 54 additions & 0 deletions src/functional-recursion/lib/math_operations.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
defmodule MathOperations do
def print([]) do
IO.puts("Fim da lista")
end

def print(list) do
head = hd(list)
tail = tl(list)

IO.puts(head)
print(tail)
end

def sum_numbers([]) do
0
end

def sum_numbers(numbers) do
[head | tail] = numbers

head + sum_numbers(tail)
end

def sum_numbers_tr([], sum) do
sum
end

def sum_numbers_tr(numbers, sum) do
[head | tail] = numbers

temp_sum = head + sum
sum_numbers_tr(tail, temp_sum)
end

def double([]) do
[]
end

def double([head | tail]) do
[head * 2 | double(tail)]
end

def double_tr(list, list \\ [])
def double_tr([], list), do: Enum.reverse(list)

def double_tr(numbers, list) do
head = hd(numbers)
tail = tl(numbers)

double = head * 2

double_tr(tail, [double | list])
end
end
35 changes: 35 additions & 0 deletions src/functional-recursion/lib/parentheses.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
defmodule Parentheses do
def is_parentheses_valid?(text) do
validate_recursive(String.graphemes(text), [])
end

defp validate_recursive([], []), do: true

defp validate_recursive([], _stack), do: false

defp validate_recursive(["(" | tail], stack) do
validate_recursive(tail, [")" | stack])
end

defp validate_recursive([")" | tail], [")" | tail_stack]),
do: validate_recursive(tail, tail_stack)

defp validate_recursive([_ | tail], stack) do
validate_recursive(tail, stack)
end

def is_parentheses_valid_iterative?(text) do
count =
text
|> String.graphemes()
|> Enum.reduce(0, fn char, count ->
case char do
"(" -> count + 1
")" -> count - 1
_ -> count
end
end)

count == 0
end
end
30 changes: 30 additions & 0 deletions src/functional-recursion/mix.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
defmodule Fibonacci.MixProject do
use Mix.Project

def project do
[
app: :fibonacci,
version: "0.1.0",
elixir: "~> 1.16",
start_permanent: Mix.env() == :prod,
deps: deps()
]
end

# Run "mix help compile.app" to learn about applications.
def application do
[
extra_applications: [:logger]
]
end

# Run "mix help deps" to learn about dependencies.
defp deps do
[
{:benchee, "~> 1.3"},
{:dialyxir, "~> 1.4", only: [:dev, :test], runtime: false},
# {:dep_from_hexpm, "~> 0.3.0"},
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
]
end
end
7 changes: 7 additions & 0 deletions src/functional-recursion/mix.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
%{
"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"},
"deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"},
"dialyxir": {:hex, :dialyxir, "1.4.3", "edd0124f358f0b9e95bfe53a9fcf806d615d8f838e2202a9f430d59566b6b53b", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "bf2cfb75cd5c5006bec30141b131663299c661a864ec7fbbc72dfa557487a986"},
"erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
"statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"},
}
27 changes: 27 additions & 0 deletions src/functional-recursion/test/fibonacci_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
defmodule FibonacciTest do
use ExUnit.Case
doctest Fibonacci

test "fibonacci" do
assert Fibonacci.fib(2) == 1
assert Fibonacci.fib(6) == 8
assert Fibonacci.fib(10) == 55
end

test "fibonacci tail call optimization" do
assert Fibonacci.fib_tco(2) == 1
assert Fibonacci.fib_tco(6) == 8
assert Fibonacci.fib_tco(10) == 55
end

test "Benchmark" do
n = 20

Benchee.run(
%{
"fibonacci" => fn -> Fibonacci.fib(n) end,
"fibonacci with tail-call optimization" => fn -> Fibonacci.fib_tco(n) end
},
print: [fast_warning: false])
end
end
38 changes: 38 additions & 0 deletions src/functional-recursion/test/math_operations_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
defmodule RecursionTest do
use ExUnit.Case

test "sum_numbers" do
assert MathOperations.sum_numbers([1, 2, 3, 4]) == 10
assert MathOperations.sum_numbers_tr([1, 2, 3, 4], 0) == 10
end

test "Sum numbers benchmark" do
array = 0..1000 |> Enum.to_list()

Benchee.run(
%{
"Body recursive" => fn -> MathOperations.sum_numbers(array) end,
"Tail recursive" => fn -> MathOperations.sum_numbers_tr(array, 0) end
},
print: [fast_warning: false]
)
end

test "Double numbers in array" do
assert MathOperations.double([1, 2, 3, 4]) == [2, 4, 6, 8]
assert MathOperations.double_tr([1, 2, 3, 4]) == [2, 4, 6, 8]
end

@tag skip: true
test "Double numbers benchmark" do
array = 0..1000 |> Enum.to_list()

Benchee.run(
%{
"Body recursive" => fn -> MathOperations.double(array) end,
"Tail recursive" => fn -> MathOperations.double_tr(array) end
},
print: [fast_warning: false]
)
end
end
39 changes: 39 additions & 0 deletions src/functional-recursion/test/parentheses_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
defmodule ParenthesesTest do
use ExUnit.Case

test "Validate parentheses recursive" do
assert Parentheses.is_parentheses_valid?("(text)") == true
assert Parentheses.is_parentheses_valid?("((text))") == true
assert Parentheses.is_parentheses_valid?("()()") == true
assert Parentheses.is_parentheses_valid?("(text") == false
assert Parentheses.is_parentheses_valid?("(text)(") == false
assert Parentheses.is_parentheses_valid?("((text") == false
end

test "Validate parentheses iterative" do
assert Parentheses.is_parentheses_valid_iterative?("(text)") == true
assert Parentheses.is_parentheses_valid_iterative?("((text))") == true
assert Parentheses.is_parentheses_valid_iterative?("()()") == true
assert Parentheses.is_parentheses_valid_iterative?("(text") == false
assert Parentheses.is_parentheses_valid_iterative?("(text)(") == false
assert Parentheses.is_parentheses_valid_iterative?("((text") == false
end

@tag skip: true
test "Validate parentheses benchmark" do
inputs = %{
"case single pair valid" => "(text)",
"case double pair valid" => "((text))",
"case long text valid" => "(fdsfsfddsfsdfsdfsfsdfddsdfddddsdfsfsdfsdfsdfsdfsdfdsf)",
"case long text invalid" => "fdsdfsfddsfsdfsdfsfsdfddsdfddddsdfsfsdfsdfsdfsdfsdfdsf)"
}

Benchee.run(
%{
"Recursive" => fn input -> Parentheses.is_parentheses_valid?(input) end,
"Iterative" => fn input -> Parentheses.is_parentheses_valid_iterative?(input) end
},
inputs: inputs,
print: [fast_warning: false])
end
end
1 change: 1 addition & 0 deletions src/functional-recursion/test/test_helper.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ExUnit.start()

0 comments on commit 08e665f

Please sign in to comment.