Imagine que queremos aplicar uma série de funções xse, e somente se, xnão for nulo:
if (x !== null) x = a(x);
if (x !== null) x = b(x);
if (x !== null) x = c(x);
Agora, digamos que precisamos fazer o mesmo para y:
if (y !== null) y = a(y);
if (y !== null) y = b(y);
if (y !== null) y = c(y);
E o mesmo para z:
if (z !== null) z = a(z);
if (z !== null) z = b(z);
if (z !== null) z = c(z);
Como você pode ver, sem uma abstração adequada, acabaremos duplicando o código continuamente. Essa abstração já existe: a mônada Maybe .
A mônada Maybe contém um valor e um contexto computacional:
- A mônada mantém o valor seguro e aplica funções a ele.
- O contexto computacional é uma verificação nula antes de aplicar uma função.
Uma implementação ingênua seria assim:
⚠️ Esta implementação é apenas para fins ilustrativos! Não é assim que deve ser feito e está errado em muitos níveis. No entanto, isso deve dar a você uma idéia melhor do que estou falando.
Como você pode ver, nada pode quebrar:
- Aplicamos uma série de funções ao nosso valor
- Se em algum ponto o valor se tornar nulo (ou indefinido), simplesmente não aplicamos mais nenhuma função.
const abc = obj =>
Maybe
.of(obj)
.map(o => o.a)
.map(o => o.b)
.map(o => o.c)
.value;
const values = [
{},
{a: {}},
{a: {b: {}}},
{a: {b: {c: 42}}}
];
console.log(
values.map(abc)
);
<script>
function Maybe(x) {
this.value = x; //-> container for our value
}
Maybe.of = x => new Maybe(x);
Maybe.prototype.map = function (fn) {
if (this.value == null) { //-> computational context
return this;
}
return Maybe.of(fn(this.value));
};
</script>
Apêndice 1
Não posso explicar o que são mônadas, pois este não é o propósito deste post e existem pessoas melhores nisso do que eu. No entanto, como Eric Elliot disse em sua postagem em seu blog JavaScript Monads Made Simple :
Independentemente do seu nível de habilidade ou compreensão da teoria das categorias, o uso de mônadas facilita o trabalho com o código. Deixar de tirar proveito das mônadas pode tornar seu código mais difícil de trabalhar (por exemplo, inferno de callback, ramificações condicionais aninhadas, mais verbosidade).
Apêndice 2
Veja como eu resolveria seu problema usando a mônada Maybe demonetjs
const prop = key => obj => Maybe.fromNull(obj[key]);
const abc = obj =>
Maybe
.fromNull(obj)
.flatMap(prop('a'))
.flatMap(prop('b'))
.flatMap(prop('c'))
.orSome('🌯')
const values = [
{},
{a: {}},
{a: {b: {}}},
{a: {b: {c: 42}}}
];
console.log(
values.map(abc)
);
<script src="https://www.unpkg.com/monet@0.9.0/dist/monet.js"></script>
<script>const {Maybe} = Monet;</script>
try..catchinstrução. Dito isso, uma matriz que contém elementos extremamente heterogêneos parece um problema de design para mim.