Programação Funcional Avançada: Monads em JavaScript

Você já percebeu que cada vez mais o termo Programação Funcional vem sendo usado pela comunidade?

No meu último post, Entendendo Programação Funcional em JavaScript de uma vez, expliquei os conceitos mais básicos. Porém, esse artigo vai mostrar os detalhes mais técnicos pra quem quer se aprofundar e entender de vez o assunto.

Então, continue lendo esse post para aprender:
1. Composição de funções
2. Pointfree functions
3. Utilizar pipes com o Pareto.js
4. O que são Monads


Composição de Funções

Se você já entendeu o básico da Programação Funcional, percebeu que um dos principais objetivos é construir funções pequenas (e puras) para que possamos compô-las e desenvolver outra funções maiores e mais complexas.

Com isso em mente, vamos construir uma solução funcional para gerar um slug simples de uma string:

slug('Novo Post No Blog') // novo-post-no-blog

Ou seja, recebemos uma string como parâmetro e retornamos uma transformação dessa string: 1) aplicamos um lowercase e 2) fazemos a substituição de espaços por traços.

O código simples abaixo resolve esse problema:

A função slug, que é a função principal, recebe uma string title como parâmetro, depois aplica a função toLowerCase em title e retorna esse valor para que a função replaceSpaces retorne a nova string transformada.

Dessa forma:

slug('Novo Post No Blog');
1. toLowerCase('Novo Post No Blog');
2. replaceSpaces('novo post no blog');
3. 'novo-post-no-blog'

Em resumo, a função slug é uma composição de funções.


Apesar de já estarmos num caminho mais funcional, ainda temos alguns problemas com a função slug. A legibilidade é um deles:

const slug = title => replaceSpaces(toLowerCase(title))

Lemos a função da esquerda para a direita:
1. replaceSpaces
2. toLowerCase

Só que a função slug, como mostrei anteriormente, aplica essas duas funções na ordem contrária da forma que lemos.

Como resolver esse problema?

Pipes

Composição de funções é algo tão comum ao usar o paradigma funcional, que um padrão comum para fazer essa composição é usar pipes.

O JavaScript não vem com uma função pipe na própria linguagem, portanto vamos usar uma lib funcional para isso. Poderíamos usar o Ramda.js sem nenhum problema, mas nesse exemplo vou usar o Pareto.js, que é bem semelhante ao Ramda.js só que é lightweight e mais moderno.

Com a função pipe então, o problema estaria resolvido dessa forma:

Dessa forma atingimos o primeiro objetivo, que era de melhorar a ordem da leitura da função que agora está mais natural: da esquerda para a direita.

Além disso, conseguimos também uma outra vantagem mais sutil.

Leia novamente as duas versões da função slug:

A nova versão não contém nenhuma referência ao parâmetro title que será passado. Isso tem um nome: pointfree function.

Com isso não ficamos tão acoplados a um nome específico do parâmetro e temos uma função mais flexível a possíveis mudanças e mais fácil de ler.

Null

A nossa função slug funciona muito bem, só tem um problema: no mundo real, eventualmente passamos null como parâmetro. Nesse caso a função quebraria e nós nem saberíamos o que aconteceu.

Podemos resolver de uma forma simples:

Mas essa solução não é muito escalável: precisamos colocar a verificação de null em todas nossas funções, que deveriam ser simples e focadas em resolver apenas um problema.

Seria bem mais simples centralizar essa checagem em um único lugar.

Monads

Um Monad, resumidamente, é simplesmente um wrapper de um valor qualquer. A função Maybe abaixo faz exatamente isso:

Com isso já temos um wrapper, mas ainda faltam alguns detalhes.

Primeiramente vamos fazer um refactoring na função Maybe, para tirar proveito de alguns benefícios do ES6.

Vamos transformar então disso:

Para isso:

Como nosso principal objetivo com os Monads é ter uma garantia em relação ao null, vamos adicionar uma função isNothing que faz essa verificação:

Pra finalizar nosso Monad, precisamos de uma nova função que:
1. Aplique uma outra função ao valor do wrapper, caso esse valor exista
2. Não faça nada, caso o valor seja null

Agora que temos a versão finalizada do Maybe Monad, precisamos apenas atualizar a versão inicial da função slug:

Feito isso, conseguimos compor funções de forma funcional e nos proteger do null.

Lembrando que precisamos fazer tudo isso, porque o JavaScript não é uma linguagem 100% funcional. Elm por exemplo, já vem com tudo o que fizemos nesse post construído na própria linguagem.

Se quiser saber mais sobre Elm, sugiro ler o post Elm: Programação Funcional no Front-End do jeito certo.


Se você gostou do post não se esqueça de dar um ❤ aqui embaixo!
E se quiser receber de antemão mais posts como esse,
assine nossa newsletter.

Seja um apoiador, doe BitCoins: 1BGVKwjwQxkr3w1Md2X8WHAsyRjDjyJiPZ

JSCasts

É difícil encontrar conteúdo bom e atualizado em português. Com isso em mente criamos o JSCasts, onde você vai se manter em dia com o JavaScript e todo o seu ecossistema de forma fácil e interativa.

Cursos:

Obrigado por ler! ❤