PROGRAMAÇÃO
FUNCIONAL
EM
JAVASCRIPT
PROGRAMAÇÃO
FUNCIONAL
EM
JAVASCRIPT
COMO E POR QUÊ?
Sim, é minha única foto boa e eu uso ela pra tudo.
Estudante de Ciência da Computação apaixonado por
programação funcional e pesquisador independente
(do grego: de mentira) em linguagens de programação.
Não tenho muita coisa interessante pra falar de mim
mesmo então vou preencher o slide com lorem ipsum
dolor sit amet, consectetur adipiscing elit.
ARTHUR
XAVIER
— BRET VICTOR
“A tecnologia muda rápido, mas o modo
de pensar das pessoas muda devagar.”
THE FUTURE OF
PROGRAMMING
BRET VICTOR
youtu.be/8pTEmbeENF4
“Pode haver muita resistência a
novas formas de trabalho que
demandem que você desaprenda o
que já aprendeu e pense de forma
diferente.”
s : → ℤ = α ↦
0 se α = ε
x + s(β) se α = x • β
f : ℤ → ℕ = x ↦ |x|JEITO
ESTILO
PARADIGMAMINDSET
O QUE É
PROGRAMAR?
TRANSFORMAR
PROBLEMAPROBLEMAPROBLEMAPROBLEMAPROBLEMA
TRANSFORMAR
SOLUÇÃO
PROBLEMAPROBLEMAPROBLEMAPROBLEMAPROBLEMA
DECOMPOR
SOLUÇÃO
DECOMPOR
MINDSET
:(
λ?
PROGRAMAÇÃO
IMPERATIVA
PROGRAMAÇÃO
DECLARATIVA
VS.
// const values : Array<number>;
console.log(values.map(x => x*x));
// const values : Array<number>;
let squares = [];
for (let value of values) {
squares.push(value*value);
}
console.log(squares);
// const names : Array<string>;
let promises = [];
for (let name of names) {
promises.push(name);
}
Promise.all(promises);
// const names : Array<string>;
Promise.all(names.map(getUserByName));
// const userId : string;
const steps = [
removeUserComments,
removeUserPosts,
removeUserFriends,
removeUserData,
];
for (let step of steps) {
await step(userId);
}
// const userId : string;
// Promise.sequence = ps => Promise.reduce(ps, (_, p) => p);
const steps = [
removeUserComments,
removeUserPosts,
removeUserFriends,
removeUserData,
];
return Promise.sequence(steps.map(step => step(userId)));
// const userIds : Array<string>;
const steps = [
removeUserComments,
removeUserPosts,
removeUserFriends,
removeUserData,
];
for (let step of steps) {
const promises = userIds.map(userId => step(userId);
await Promise.all(promises);
}
// const userIds : Array<string>;
const steps = [
removeUserComments,
removeUserPosts,
removeUserFriends,
removeUserData,
];
const runStepOnUsers = step => Promise.all(userIds.map(step));
const allSteps = steps.map(runStepOnUsers);
return Promise.sequence(allSteps);
PROGRAMAÇÃO
IMPERATIVA
PROGRAMAÇÃO
DECLARATIVA
VS.
λ¿
— EU
“Paradigma de programação onde computações são
representadas por funções ou expressões puras,
evitando efeitos colaterais e dados mutáveis, e que
utiliza amplamente de composição de funções e
funções de primeira classe.”
≠FUNÇÃO PROCEDIMENTO
X Y
x
f(x)
f : X → Y
FUNÇÃO (PURA)
— WIKIPEDIA
“Uma função ou expressão produz efeitos colaterais se ela
modifica algum estado fora de seu escopo ou realiza
alguma interação observável com as funções que a
chamaram ou com o mundo externo.”
function append(x) {
this.array.push(x);
}
function appendTo(array, x) {
array.push(x);
}
function appendTo(array, x) {
return [...array, x];
}
IMUTABILIDADE
function increment(counter) {
counter.value += 1;
}
function increment(counter) {
return {
...counter,
value: counter.value + 1,
};
}
EFEITOS COLATERAIS
function sumOfSquares(array) {
let result = 0;
for (let x of array) {
result += x*x;
}
console.log(result);
};
function onNotification(notification) {
const message = notification.getMessage();
NotificationManager.addNotification(message);
ObscureObject1.obscureMethod1(notification);
ObscureObject2.obscureMethod2(notification);
ObscureObject3.obscureMethod3(notification);
// ...
};
function sumOfSquares(array) {
let result = 0;
for (let x of array) {
result += x*x;
}
return result;
};
console.log(sumOfSquares([2, 3, 5]));
const square = x => x*x;
const add = (a, b) => a + b;
function sumOfSquares(array) {
return array.map(square).reduce(add, 0);
}
console.log(sumOfSquares([2, 3, 5]));
FUNÇÕES
PURAS
1 Fáceis de testar;
2 Fáceis de entender;
3 Componíveis;
4 Determinísticas.
Fáceis de testar;
Fáceis de entender;
Componíveis;
Determinísticas.
FUNÇÕES
PURAS
1 Fáceis de testar;
2 Fáceis de entender;
3 Componíveis;
4 Determinísticas.
Cacheáveis;
Portáveis;
Paralelizáveis;
Simples.
EFEITOS COLATERAIS?
EFEITOS!
DADOS
EFEITOS
EFEITOS
EFEITOS
EFEITOS
function* watchLoadMoreStarred() {
while (true) {
const {login} = yield take(actions.LOAD_MORE_STARRED);
yield fork(loadStarred, login, true);
}
}
function* loadStarred(login, loadMore) {
const starredByUser = yield select(getStarredByUser, login);
if (!starredByUser || loadMore)
yield call(fetchStarred, login, starredByUser.nextPageUrl);
}
function* watchLoadMoreStarred() {
while (true) {
const {login} = yield take(actions.LOAD_MORE_STARRED);
yield fork(loadStarred, login, true);
}
}
function* loadStarred(login, loadMore) {
const starredByUser = yield select(getStarredByUser, login);
if (!starredByUser || loadMore)
yield call(fetchStarred, login, starredByUser.nextPageUrl);
}
function* watchLoadMoreStarred() {
while (true) {
const {login} = yield take(actions.LOAD_MORE_STARRED);
yield fork(loadStarred, login, true);
}
}
function* loadStarred(login, loadMore) {
const starredByUser = yield select(getStarredByUser, login);
if (!starredByUser || loadMore)
yield call(fetchStarred, login, starredByUser.nextPageUrl);
}
function* watchLoadMoreStarred() {
while (true) {
const {login} = yield take(actions.LOAD_MORE_STARRED);
yield fork(loadStarred, login, true);
}
}
function* loadStarred(login, loadMore) {
const starredByUser = yield select(getStarredByUser, login);
if (!starredByUser || loadMore)
yield call(fetchStarred, login, starredByUser.nextPageUrl);
}
FUNÇÕES DE PRIMEIRA CLASSE
=FUNÇÃO VALOR
function* watchLoadMoreStarred() {
while (true) {
const {login} = yield take(actions.LOAD_MORE_STARRED);
yield fork(loadStarred, login, true);
}
}
function* loadStarred(login, loadMore) {
const starredByUser = yield select(getStarredByUser, login);
if (!starredByUser || loadMore)
yield call(fetchStarred, login, starredByUser.nextPageUrl);
}
FUNÇÕES DE ALTA ORDEMALTA
ABSTRAÇÃOABSTRAÇÃOABSTRAÇÃOABSTRAÇÃOABSTRAÇÃOABSTRAÇÃOABSTRAÇÃOABSTRAÇÃOABSTRAÇÃOABSTRAÇÃOABSTRAÇÃO
OTIMIZAÇÃO
ABSTRAÇÃOABSTRAÇÃOABSTRAÇÃOABSTRAÇÃOABSTRAÇÃOABSTRAÇÃOABSTRAÇÃOABSTRAÇÃOABSTRAÇÃOABSTRAÇÃOABSTRAÇÃO
mapfilter reduce
function buildElements(n, factory) {
return Array(n).fill(0)
.map(Math.random)
.map(factory);
}
appendToDom(10, x => <h2>{x}</h2>);
function buildElements(n, factory) {
return Array(n).fill(0)
.map(Math.random)
.map(factory);
}
appendToDom(10, h2);
function buildElements(n, factory) {
return Array(n).fill(0)
.map(Math.random)
.map(factory);
}
appendToDom(10, small);
λ!
function buildElements(n, factory) {
return Array(n).fill(0)
.map(() => factory(Math.random()));
}
appendToDom(10, h2);
function buildElements(n, factory) {
return Array(n).fill(0)
.map(compose(factory, Math.random));
}
appendToDom(10, h2);
λ!
DESIGN PATTERNS?
MATEMÁTICA!
function getUserAndFriends(id) {
return Promise.all([
getUserData({ id }),
getUserFriends({ id }),
])
.then([user, friends] => ({
...user,
friends,
});
}
function getFriendsOfFirstFriend(id) {
return getUserFriends({ id })
.then(friends => getUserData(friends[0]))
.then(getUserFriends);
}
function getAvatarURL(user) {
return Maybe(user)
.then(user => user.avatar)
.then(avatar => avatar.url);
}
getAvatarURL({ avatar: { url: 'barbaz' } });
// == Maybe('test')
getAvatarURL(null);
// == Maybe(null)
getAvatarURL({ name: 'foobar' });
// == Maybe(null)
function Do(m, f) {
const gen = f();
function doRec(v = undefined) {
const {value, done} = gen.next(v);
const valueM = value instanceof m ? value : m.of(value);
return done ? valueM : valueM.then(doRec);
}
return doRec();
}
function generateUserURL(userMaybe) {
return Do(Maybe, function*() {
let user = yield userMaybe;
let name = yield user.name;
return user.hasPage ? nameToURL(name) : null;
});
}
generateUserURL({ name: 'foobar', hasPage: true });
// == Maybe('https://fezbok/foobar')
generateUserURL({ name: 'barbaz' });
// == Maybe(null)
generateUserURL(null);
// == Maybe(null)
getAvatarURL({ hasPage: true });
// == Maybe(null)
// Promise.of = Promise.resolve;
Do(Promise, function*() {
const friends = yield getUserFriends({ id });
const firstFriend = yield getUserData(friends[0]);
return getUserFriends(firstFriend);
});
async function getFriendsOfFirstFriend(id) {
const friends = await getUserFriends({ id });
const firstFriend = await getUserData(friends[0]);
return getUserFriends(firstFriend);
}
λ!
?
1Evite mutação
Use dados e APIs imutáveis e sempre use const ao invés de let e var.
Reduz o risco de estado compartilhado;
2Evite dependências implícitas
Podem trazer efeitos colaterais indesejados e estado compartilhado.
this é uma dependência implícita;
3Desacople dados e comportamento
Pense em unidades de trabalho pequenas e genéricas.
Abstraia e componha.
— EU
“Programação funcional é uma ótima
ferramenta para controle de complexidade.”
O(n²)
AbstractSingletonProxyFactoryBeanImpl
1 Difícil de identificar e
decompor em partes;
2 Depende de recursos
compartilhados;
3 Ligado a uma ordem
de execução predefinida.
CÓDIGO
IMPERATIVO É
DIFÍCIL
DE TESTAR
Difícil de identificar e
decompor em partes;
Depende de recursos
compartilhados;
Ligado a uma ordem de
execução predefinida.
1 Difícil de identificar e
decompor em partes;
2 Depende de recursos
compartilhados;
3 Ligado a uma ordem
de execução predefinida.
CÓDIGO
IMPERATIVO É
DIFÍCIL
DE REFATORAR
Difícil de identificar e
decompor em partes;
Depende de recursos
compartilhados;
Ligado a uma ordem de
execução predefinida.
1 Difícil de identificar e
decompor em partes;
2 Depende de recursos
compartilhados;
3 Ligado a uma ordem de
execução predefinida.
CÓDIGO
IMPERATIVO É
DIFÍCIL
DE ENTENDER
Difícil de identificar e
decompor em partes;
Depende de recursos
compartilhados;
Ligado a uma ordem de
execução predefinida.
CÓDIGO
FUNCIONAL É
FÁCIL
DE ENTENDER
1 Difícil de identificar e
decompor em partes;
2 Depende de recursos
compartilhados;asdasda
sdas
3 Ligado a uma ordem de
execução predefinida.
Força a decomposição
de tarefas complexas;
Abstrai e generaliza
estruturas de controle
de fluxo;
Completamente
previsível.
REQUER
DESAPRENDER
REQUER
REAPRENDER
Brian Lonsdorf (Dr. Boolean)
PROFESSOR FRISBY’S
MOSTLY ADEQUATE GUIDE
TO FUNCTIONAL
PROGRAMMING
Luis Atencio
FUNCTIONAL
PROGRAMMING
IN JAVASCRIPT
Evan Czaplicki
ELM
@arthurxavierx @arthur-xavier
goo.gl/kL4SNH

Programação funcional em JavaScript: como e por quê?