# Programação Funcional com Elixir
## O que é programação funcional?
- Paradigma de programação
- Evita mutação
- Alto nível de abstração
- Funções que computam o estado baseado na entrada
### Lambda Calculus
- Sistema formal que estuda funções recursivas
- Criado por Alonzo Church na década de 30
### Características de uma Linguagem Funcional
- Funções de alta ordem:
- Passagem de funções por parâmetro
- Retorno de funções por outras funções
- Composição de funções
- Funções anônimas
### Mutabilidade x Imutabilidade
#### Mutabilidade
- É possível alterar o valor de uma variável
- Tenho estado dentro de objetos
- Comum em linguagens orientadas a objeto
Os códigos abaixo nos mostra alguns exemplos de mutabilidade:
```ruby
numbers = [25]
numbers << 26
numbers << 27
numbers
# => [25, 26, 27]
```
```ruby
text = "Hello"
text.upcase!
text
# => "HELLO"
```
```ruby
class Product
def initialize(name:, price:)
@name = name
@price = price
end
attr_accessor :name, :price
end
product = Product.new(name: 'Notebook', price: 1500.99)
# => #<Product:0x00005606bf4d47b8 @name="Notebook", @price=1500.99>
product.price = 255.99
product
# => #<Product:0x00005606bf4d47b8 @name="Notebook", @price=255.99>
```
Em linguagens orientadas a objeto não temos separação de dados e operações, geralmente utilizamos `métodos` no próprio objeto.
#### Imutabilidade
- Não é possível alterar valores definidos
- Uma função sempre irá retornar o mesmo resultado
- Evita efeitos colaterais
- Ideal para ambientes concorrentes e paralelos
- Príncipio fundamental em linguagens funcionais
```elixir
numbers = [25]
List.insert_at(numbers, -1, 26)
# [25, 26]
numbers
# [25]
```
### Funções Puras e Impuras
#### Função Pura
- A execução de uma função com a mesma entrada sempre retornará o mesmo resultado
- Facilita a previsibilidade
```elixir
defmodule Speed do
def calculate(space, time) do
space / time
end
end
Speed.calculate(50, 0.5)
# 100.0
25 + 25
# 50
```
#### Função Impura
- Não é retornado o mesmo resultado mesmo quando a entrada é a mesma
- Requisições HTTP
- Tudo que envolva rede e banco de dados
- Convivemos com funções impuras e puras em um sistema
```elixir
Enum.random(0..1000)
```
### Composição de Funções

- Construir um resultado por meio da execução de mais de uma função
- O resultado da execução de uma função é passado para a próxima
```elixir
numbers = [1, 2, 3, 4, 5]
numbers
|> List.insert_at(-1, 6)
|> List.insert_at(-1, 7)
|> Enum.sum()
# 28
```
### Funções de alta ordem
```elixir
Enum.each([1, 2, 3], fn number -> IO.puts(number) end)
```
### Recursão

- Uma função chamando ela mesma
- Utilizada para "simplificar" problemas
- Alocação de pilha de execução
- Tail Call Optimization
```elixir
defmodule Factorial do
def calculate(0), do: 1
def calculate(number), do: number * calculate(number - 1)
end
```
Função de fatorial otimizada pela técnica de Tail Call Optimization:
```elixir
defmodule Factorial do
def calculate(number), do: calculate(number, 1)
def calculate(0, total), do: total
def calculate(number, total), do: calculate(number - 1, total * number)
end
```
### Currying
- Decomposição de funções
- Converter uma função com múltiplos parâmetros em várias funções com um único parâmetro
- Uma função é aplicada parcialmente sobre seus parâmetros
```elixir
multiply = fn x, y -> x * y end
double = fn x -> multiply.(2, x) end
double.(2)
```
## Elixir
### Características da Linguagem
- Funcional
- É executada em uma VM existente (Erlang)
- Tipagem dinâmica
- Modelada para concorrência (processos leves)
- Tolerante a falhas
- Extensível por meio de macros
### Qual o motivo de escolher Elixir?
- Syntax amigável (baseada no Ruby)
- Excelente ecossistema e documentação
- Phoenix Framework
### Iniciando
- Instalando a linguagem (https://asdf-vm.com/#/plugins-all)
- Erlang
- Elixir
- IEx: Elixir's interactive shell (REPL)
- Mix: Ferramenta para criar projetos, executar tarefas, build
### Hello World
```elixir
IO.puts("Hello World")
```
Você pode criar um arquivo com a extensão `.ex`:
`sum.ex`
```elixir
IO.puts(10 + 25)
```
E para executar:
```
$ elixir sum.ex
```
Ou então utilizá-lo dentro do `iex`:
```
c("sum.ex")
```
### Tipos
- integer => 1
- float => 1.0
- boolean => true/false
- atom => :test
- string => "teste"
- list => [1, 2, 3, 4]
- tuple => {:ok, "OK"}
- map => %{name: "Blah", age: 25}
### Variáveis
```elixir
number = 10
number * 10
```
### Pattern Matching
```elixir
a = 10
10 = a
defmodule Example do
def hello(10), do: 10
def hello(20), do: 20
end
{a, b, c} = {:hi, :hello, 25}
[a, b] = [1, 2]
[head | tail] = [1, 2, 3, 4, 5]
x = 10
{:ok, ^x} = {:ok, 10}
```
### Estruturas de Controle
```elixir
number = 25
if number > 25 do
IO.puts(">")
else
IO.puts("<")
end
cond do
number == 26 -> IO.puts(26)
number == 27 -> IO.puts(27)
end
case {1, 2, 3} do
{a, _b, _c} when a == 1 -> :ok
_ -> :error
end
```
### Módulos e Funções
```elixir
defmodule MyFirstModule do
@hello "hello world"
def hello do
@hello
end
end
```
### Enumeração e Listas
```elixir
Enum.map([1, 2, 3], fn number -> number * 3 end)
Enum.filter([1, 2, 3], &(&1 == 1))
```
## OTP
### Processos
```elixir
self()
pid = spawn(fn -> IO.puts("Hello!") end)
Process.alive?(pid)
```
### Comunicação entre Processos
```elixir
send(self(), "Hey!")
flush()
```
### GenServers
### Supervisors
### Erlang Distribuído
## Primeiro Projeto: Controle de despesas pessoais
Criar uma aplicação que recebe um csv com as entradas de uma fatura de cartão de crédito com as seguintes funções:
- Agrupar gastos da mesma categoria
- Valor total
- Cateogoria com maiores gastos
- As compras de maior valor
- Dia com o maior número de transações (quantidade x valor)
## Segundo Projeto: Gerenciamento de carteira de investimentos