---
# System prepended metadata

title: Programação Funcional com Elixir

---

# 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

![](https://i.imgur.com/G4emEVZ.png)


- 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

![](https://i.imgur.com/hhOdHMO.png)


- 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 