Programação funcional em Javascript. Desconstruindo o Pareto.js
Como podemos implementar Curry e Compose, com bind e reduce.


Nos últimos tempos só se fala em programação funcional, seus benefícios, funções puras, dados imutáveis, composição de funções, etc. Caso precise de saber mais, recomendo esse post do Matheus Lima:
Você já percebeu que cada vez mais o termo Programação Funcional vem sendo usado pela comunidade?medium.com
Atualmente temos diversas libs que auxiliam o javascript na missão de ser funcional, Lodash, Underscore e Ramda são uma delas. Então porque estarei falando do Pareto.js? Simples como o Princípio de Pareto, a lib criada tem o objetivo de ser leve e resolver 80% dos seus problemas com 20% de código.
pareto.js - A small trully functional utility library that only has what you really need.github.com
Geralmente procuro aprender algo desmitificando a “mágica” por trás da implementação. Foi assim quando comecei a aprender Angular, e agora o mesmo está sendo aplicado à programação funcional. Por isso nesse post vamos avaliar as implementações de Curry e Compose do Pareto.js.
Curry
Curry é a ação de pegar uma função que receba múltiplos argumentos e transformá-la em uma cadeia de funções, em que cada uma receba somente um parâmetro.
Vamos agora ver o teste dessa função:
Para começarmos a desmitificar a mágica, temos duas perguntas a serem feitas:
- Como a nossa função curry irá armazenar os parâmetros já passados?
- O que o Function.prototype.bind() tem a ver com isso?
Function.prototype.bind()
Comumente usamos .bind() para passarmos para uma função um contexto para sua execução, porém nos esquecemos de algo importante, como dito na documentação do developer.mozilla.org:
Partial Functions
The next simplest use of bind() is to make a function with pre-specified initial arguments. These arguments (if any) follow the provided this value and are then inserted at the start of the arguments passed to the target function…
Resumindo:
Um dos usos de bind() é construir uma função com argumentos iniciais pré-especificados. Esses argumentos, serão passados após o valor de This e serão inseridos no inicio dos argumentos passados para a função de destino…
Difícil de entender? Então vamos a mais um exemplo (em ES5 para que você possa abrir o devtools e já testar).
Reparem que a função myNumbers espera três parâmetros, a cada vez que chamamos .bind(this, val), a função retornada pelo método .bind() automagicamente guarda o argumento passado.
E com isso chegamos à implementação do curry no pareto.js, que irá chamar curry.bind(this, fn, ...args), empilhando os parâmetros no spread operator ...args até que a quantidade de argumentos seja a mesma que a função espera (args.length === fn.length). Caso não tenha entendido o que é …args, dê uma lida em spread operator.
Compose
Como o próprio nome sugere, Compose é construir funções mais complexas através de funções mais simples, compondo-as. Vamos à implementação no Pareto.js:
Vamos ao teste dessa função:
E assim temos uma pergunta:
- O que Array.prototype.reduce() está fazendo aí no meio ?
Array.prototype.reduce()
Em geral pensamos no .reduce() como um acumulador, porém somente no sentido de soma de valores e não de composição. Sabemos que o .reduce() aplica uma função de callback sobre um acumulador, varrendo todos os elementos do array. Vamos começar a desconstrução do nosso compose:
- Sabemos que ele recebe um array de funções como argumentos, através do spread operator …args;
- A função de callback do .reduce(), que será executada sobre cada item do nosso array, pode receber até 4 parâmetros, sendo eles: previousValue, currentValue, index, array. Porém aqui só iremos utilizar os dois primeiros (previousValue e currentValue). Lembrando que na primeira chamada à nossa função de callback, previousValue será o valor do primeiro elemento do array e currentValue será o valor do elemento seguinte;
- A nossa função de callback irá compor a função passada em previousValue com a que está em currentValue, adicionando na declaração da função que ela poderá receber N argumentos (…args). Resultando em previousValue(currentValue(…args)).
De acordo com o nosso testes, vamos observar os passos de execução em uma tabela:

E com isso temos o resultado da função mais interna (moreExclaim) alimentando as funções mais externas (exclaim e depois toUpperCase).
E é isso pessoal. Espero que tenha ajudado à vocês a entenderem a relação de curry e compose com .bind() e .reduce(). Feedbacks são mais do que bem-vindos e incentivados. Até a proxima.
Fontes:
https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator
https:[email protected][email protected]vez-c676489be08b#
https://github.com/concretesolutions/pareto.js
https://pt.wikipedia.org/wiki/Princ%C3%ADpio_de_Pareto