Programação Funcional
Uma introdução
# whoami
root Victor Perin
- Organizador do NodeSchool Campinas
- Desenvolvedor NodeJS na InGaia
- Desculpem pelos vicios de linguagem
- ❤️ Cryptography | Cypherpunks | Bitcoins
- ❤️ JS | Docker | NoSQL
- ❤️ FP | Reactive | Async
- ❤️ Automata | Computer Science | etc
![](https://s3.amazonaws.com/media-p.slid.es/uploads/359304/images/4294083/perin.jpg)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/359304/images/4294565/pasted-from-clipboard.png)
Gimme bitcoins!1!
![](https://s3.amazonaws.com/media-p.slid.es/uploads/359304/images/4889593/pasted-from-clipboard.png)
Por que aprender?
Introdução
Em ciência da computação, programação funcional é um paradigma de programação que trata a computação como uma avaliação de funções matemáticas e que evita estados ou dados mutáveis. Ela enfatiza a aplicação de funções, em contraste da programação imperativa, que enfatiza mudanças no estado do programa.
Pédia, Wiki.
Primeiros Exemplos
function doubleItems (arr) {
let results = []
for (let i = 0; i < arr.length; i++){
results.push(arr[i] * 2)
}
return results
}
const doubleItems = (items) =>
items.map(
(item) => item * 2
)
function sumItems (arr) {
let result = 0
for (let i = 0; i < arr.length; i++){
result += arr[i]
}
return result
}
const sumItems = items =>
items.reduce(
(previous, current) => previous + current
)
Functional
Imperative
Vantagens da FP
vs OOutros paradígmas
- Mais declarativo
- Isolamento de efeitos colaterais
- Facilidade de testar
- Simplicidade matemática
- Facilidade de paralelizar
- Imutabilidade
Mitos da FP
- Ah, eu ouvi que FP gasta mais memória
- Ah, eu vejo que FP é mais complexa
- Ah, mas não tem "Design Patterns"
- Ah, mas o pessoal do trampo falou que não escala
Depende muito do Dev
Princípios
- Funções de primeira-classe
- Funções de primeira-ordem
- Map | Filter | Reduce
- Funções puras
- Imutabilidade
- Recursividade
- Otimização de chamada final
- Currying
- Composição de funções
- Pattern Matching
First-class functions
![](https://s3.amazonaws.com/media-p.slid.es/uploads/359304/images/4799314/mr-bean-gif-376222602.gif)
Funções são tratadas como first-class citizens
(são tratadas como um tipo de variável, como strings)
const sum = (a, b) => a + b
const makeSum = (a) => (b) => a + b;
High-order functions
Funções podem ser usadas como argumentos de outras funções (ex: callbacks)
const doubleMapper = (number) => number * 2
[1, 2, 3, 4].map( doubleMapper )
// [2, 4, 6, 8]
setInterval( () => console.log('data'), 3000 )
Map
Invoca a função callback passada por argumento para cada elemento do Array e devolve um novo Array como resultado.
const doubleItems = [1, 2, 3, 4].map( (number) => number * 2 )
doubleItems // [ 2, 4, 6, 8 ]
1
2
3
4
5
6
2
4
6
8
10
12
Filter
Cria um novo array com todos os elementos que passaram no teste implementado pela função fornecida.
const isOdd = (value) => value % 2
const filtered = [1, 2, 3, 4, 5, 6].filter(isOdd)
// [ 1, 3, 5 ]
1
2
3
4
5
6
1
3
5
Reduce
Utiliza uma função sobre um acumulador e cada elemento do array, reduzindo-a a um único valor.
const sumReducer = (previous, actual) =>
previous + actual
[0, 1, 2, 3, 4].reduce(sumReducer)
// 10
![](https://s3.amazonaws.com/media-p.slid.es/uploads/359304/images/4801394/reduce.gif)
Pure functions
São funções que não tem efeito colateral.
Um mesmo input sempre gera o mesmo output.
const pureFunction = (a + b) => a + b;
const b;
const impureFunction = (a) => a + b;
![](https://s3.amazonaws.com/media-p.slid.es/uploads/359304/images/4799509/side_effects_GIF-source.gif)
Imutability
É o conceito de não alterar informações.
A idéia é pensar em nunca alterar variáveis.
// puro e imutável
const counter = 0
const increments = (value = 0) => value + 1
increments(counter) // 1
increments(counter) // 1
increments(counter) // 1
// vs
// puro e mutável
let counter = 0
const increments = (value = 0) => value + 1
counter = increments(counter) // 1
counter = increments(counter) // 2
counter = increments(counter) // 3
![](https://s3.amazonaws.com/media-p.slid.es/uploads/359304/images/4799523/pass-by-reference-vs-pass-by-value-animation.gif)
PS: JavaScript não força esse conceito.
Vira responsabilidade do Dev.
Impuro / Mutável
const sales = [
{ client_id: 1 },
{ client_id: 2 },
{ client_id: 3 },
{ client_id: 4 },
]
const getClient = (id) => id + 2
const addClientsInSales = sales => {
sales.forEach( sale => {
sale.client = getClient(sale.client_id)
})
}
addClientsInSales(sales) // undefined
sales
// [
// { client_id: 1, client: 3 },
// { client_id: 2, client: 4 },
// { client_id: 3, client: 5 },
// { client_id: 4, client: 6 }
// ]
Exemplo
Resultado
Puro / Imutável
const sales = [
{ client_id: 1 },
{ client_id: 2 },
{ client_id: 3 },
{ client_id: 4 },
]
const getClient = (id) => id + 2
const addClientsInSales = sales => {
return sales.map( sale => {
return {
client: getClient(sale.client_id),
...sale
}
})
}
addClientsInSales(sales)
// [
// { client: 3, client_id: 1 },
// { client: 4, client_id: 2 },
// { client: 5, client_id: 3 },
// { client: 6, client_id: 4 }
// ]
sales
// [
// { client_id: 1 },
// { client_id: 2 },
// { client_id: 3 },
// { client_id: 4 }
// ]
Exemplo
Resultado
const sales = [
{ client_id: 1 },
{ client_id: 2 },
{ client_id: 3 },
{ client_id: 4 },
]
const getClient = (id) => id + 2
const addClientsInSales = sales =>
sales.map( sale =>
({
client: getClient(sale.client_id),
...sale
})
)
Recursion
Funções que chamam elas mesmas para processar alguma informação.
const findUsers = (ids, retries = 5) =>
database
.findUsers(ids)
.catch( (error) => {
console.error(error)
if(retries)
return findUsers(ids, retries - 1 )
})
![](https://s3.amazonaws.com/media-p.slid.es/uploads/359304/images/4893945/recursion.gif)
Tail Call Optimization
Em vez de adicionar à call stack,
você muda o ultimo item da mesma.
![](https://s3.amazonaws.com/media-p.slid.es/uploads/359304/images/4801453/callstack.gif)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/359304/images/4802121/New_Zealand_Sign_Assembly_-_Signals_Not_Working.svg.png)
const awaysExecute = (func) =>
func()
.then( () => awaysExecute(func) )
Currying
É a transformação de uma função que recebe múltiplos parâmetros de forma que ela pode ser chamada como uma cadeia de funções que recebem somente um (ou mais) parâmetro cada.
const normalFunction = (a,b,c) => a + b + c
const { curry, curryRight } = require('lodash')
const curriedFunction = curry(normalFunction)
curriedFunction(a)(b)(c)
curriedFunction(a, b)(c)
curriedFunction(a, b, c)
curriedFunction(a)(b, c)
const curriedRightFunction = curryRight(normalFunction)
curriedRightFunction(c)(b)(a)
TL:DR
uma função que pode retornar uma função para receber mais parametros.
![](https://s3.amazonaws.com/media-p.slid.es/uploads/359304/images/4802357/step11.gif)
Function Composition
É o conceito de compor 2 funções em uma única.
X ---> Y Y ---> Z
X ---> Z
const functionsToExecute = [ func1, func2, func3 ]
const { compose, reverse } = require('ramda')
const composedFunction = compose( reverse(functionToExecute) )
// function
const composedFunction = (data) =>
Promise.resolve(data)
.then(func1)
.then(func2)
.then(func3)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/359304/images/4801623/1_gmWOGIZAxdOA0Fy1p08iZQ.gif)
Pattern Matching
É o conceito de executar uma função apenas quando os dados de input batem com o padrão.
// https://github.com/tc39/proposal-pattern-matching
const res = await fetch(jsonService)
const val = match (res) {
{status: 200, headers: {'Content-Length': s}} => `size is ${s}`,
{status: 404} => 'JSON not found',
{status} if (status >= 400) => throw new RequestError(res),
default => throw default;
}
![](https://s3.amazonaws.com/media-p.slid.es/uploads/359304/images/4893851/functional-scala-18-638.jpg)
Relembrando
- Funções de primeira-classe
- Funções de primeira-ordem
- Map | Filter | Reduce
- Funções puras
- Imutabilidade
- Recursividade
- Tail Call Optimization
- Currying
- Function Composition
- Pattern Matching
![](https://s3.amazonaws.com/media-p.slid.es/uploads/359304/images/4293952/pasted-from-clipboard.png)
The End!
![](https://s3.amazonaws.com/media-p.slid.es/uploads/359304/images/4802140/pasted-from-clipboard.png)
Introdução a Programação Funcional
By Victor Perin
Introdução a Programação Funcional
- 739