Explicado em 5 minutos: Mônadas em JavaScript simples
Apesar da foto de capa intimidadora, tentarei explicar as mônadas usando o mínimo de matemática possível. Nenhuma menção à teoria da categoria, nenhum Kleisli, nem mesmo Curry. Embora haja um arquivo NaN.
Nas palavras do grande Douglas Crockford:
Além de ser bom e útil, também é amaldiçoado e a maldição da mônada é que uma vez que você tenha a epifania, uma vez que você entenda – “oh, é isso que é” – você perde a habilidade de explicá-lo a qualquer outra pessoa.
Bem, eu tenho uma teoria - isso ocorre porque entre todos os excelentes artigos sobre esse assunto, que fornecem uma ótima explicação da teoria matemática por trás das mônadas e como elas devem ser implementadas (junto com exemplos excelentes!), Uma coisa está errada:
Para que eu realmente preciso disso?
Antes de tentarmos descobrir, uma observação. Algum tempo atrás, li que você realmente não deveria tentar entender as mônadas com base em qualquer coisa que não esteja firmemente baseada na explicação da matemática por trás delas e de seu lugar na Teoria das Categorias. Para os interessados: existem alguns artigos excelentes cobrindo esse assunto, como este , ou este , ou aquele que introduziu monads na programação a partir de 1992 . Já que eu realmente não quero repeti-los aqui, por favor, leia (ou pelo menos escaneie) agora e volte aqui depois (embora eu acredite que não seja totalmente necessário entender o que acontece a seguir).
OK, agora já resolvemos isso — o que é uma mônada? Bem, a maneira mais simples de colocar isso é - é um invólucro em torno de algum valor. Em termos de programação funcional, uma mônada é um functor , uma estrutura que permite aplicar uma função a ela. É uma camada extra de abstração entre o valor e qualquer processamento pelo qual queremos passar o valor. Mas isso não nos diz nada.
Vamos dar uma olhada na mônada mais simples que você pode imaginar: uma implementação da Identitymônada:
const Identity = (value) => ({
value: () => value,
map: (fn) => Identity(fn(value)),
});
Vejamos o exemplo mais simples possível:
const addTax = (value) => value * 1.1;
const cartValue = Identity(100);
const cartValueWithTax = cartValue
.map(addTax) // At this point this is Identity(110)
.value(); // Equal to 110 as a number
A Identitymônada tem — assim como a identityfunção em muitas bibliotecas de programação funcional — uma lógica bastante transparente. É uma mônada de espaço reservado, o mesmo que identityuma função de espaço reservado. Aplicar addTaxao nosso valor funciona bem para o cenário dado acima, mas vamos pensar no que aconteceria se o valor do nosso carrinho fosse igual a undefined. Graças à maneira maravilhosa como o JavaScript funciona , obteremos um arquivo NaN.
Normalmente, para contornar isso, a maneira mais intuitiva seria adicionar uma verificação do valor à addTaxfunção. Esta é uma abordagem errada. Ela obscurece o propósito da função e a torna menos pura. A addTaxfunção deve fazer apenas uma coisa e apenas uma coisa: addo arquivo Tax.
OK, wiseguy - você pode dizer - como devemos levar o undefinedvalor em consideração? Bem, é para isso que temos mônadas. Queremos manter a função pura. Também queremos que nossa lógica se comporte de maneira diferente com base no valor que passamos para a função. O melhor lugar para definir esse comportamento é o functor !
Vejamos provavelmente a mônada mais popular que existe: Maybe. Esta pode ser uma implementação básica (estou deixando os métodos usuais que você pode encontrar em uma mônada ofpara maior clareza):
const Maybe = (value) => ({
value: () => value,
map: (fn) => value === undefined || value === null
? Maybe(null)
: Maybe(fn(value)),
});
const primitiveCart = 100;
const undefinedCart = undefined;
const nullishCart = null;
const maybeCart = Maybe(100);
const maybeUndefinedCart = Maybe(undefined);
const maybeNullishCart = Maybe(null);
addTax(primitiveCart); // boring, 110
addTax(undefinedCart); // NaN
addTax(nullishCart); // 0 - thanks, JavaScript!
maybeCart.map(addTax).value(); // 110
maybeUndefinedCart.map(addTax).value(); // null
maybeNullishCart.map(addTax).value(); // null
Isso, é claro, é apenas um arranhão na tremenda riqueza de possibilidades que o uso de mônadas traz. Digamos que queremos cumprimentar todos os hóspedes que entram em nosso hotel:
const greet = (name) => `Hello, ${name}!`;
Vamos dar uma olhada em apenas mais um exemplo elementar - a Optionalmônada:
const Optional = (value) => ({
value: () => value,
orElse: (alternativeValue) => value
? Optional(value)
: Optional(alternativeValue),
map: (fn) => Optional(fn(value)),
});
const firstGuest = "John";
const anonymousGuest = undefined;
greet(firstGuest); // "Hello, John!"
greet(anonymousGuest); // "Hello, undefined" - this is a bit embarrasing
const OptionalWithStrangerFallback = (name) => Optional(name)
.orElse("stranger");
const firstGuestOptional = OptionalWithStrangerFallback(firstGuest);
const anonymousGuestOptional = OptionalWithStrangerFallback(anonymousGuest);
// I really hope you know where this is going at this point
firstGuestOptional.map(greet).value(); "Hello, John!"
anonymousGuestOptional.map(greet).value(); "Hello, stranger!"
Eu realmente espero que isso esclareça as coisas com mônadas. Se não, por favor, deixe-me saber nos comentários! Além disso, se você quiser ler mais artigos sobre JavaScript, programação funcional, visão computacional, arquitetura, geometria, memes, liderança técnica ou qualquer combinação dos itens acima, não deixe de me seguir aqui ou no LinkedIn !





































![O que é uma lista vinculada, afinal? [Parte 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)