Concrete Logo
Hamburger button

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

  • Blog
  • 28 de Setembro de 2016
Share

*Este post foi originalmente publicado no Medium pessoal do autor. Confira aqui.

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 outras funções maiores e mais complexas.

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

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:

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:

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 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.

Então, vamos transformar 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 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 esse post aqui. Tem alguma dúvida ou alguma contribuição? Aproveite os campos abaixo!

É desenvolvedor web e quer trabalhar em um time ágil de verdade? Clique aqui.