Immagina di voler applicare una serie di funzioni a xse e solo se xnon è nullo:
if (x !== null) x = a(x);
if (x !== null) x = b(x);
if (x !== null) x = c(x);
Ora diciamo che dobbiamo fare lo stesso per y:
if (y !== null) y = a(y);
if (y !== null) y = b(y);
if (y !== null) y = c(y);
E lo stesso per z:
if (z !== null) z = a(z);
if (z !== null) z = b(z);
if (z !== null) z = c(z);
Come puoi vedere senza un'astrazione adeguata, finiremo per duplicare il codice più e più volte. Una tale astrazione esiste già: la monade Forse .
La monade Forse contiene sia un valore che un contesto computazionale:
- La monade mantiene il valore al sicuro e applica le funzioni ad esso.
- Il contesto computazionale è un controllo nullo prima di applicare una funzione.
Un'implementazione ingenua sarebbe simile a questa:
⚠️ Questa implementazione è solo a scopo illustrativo! Non è così che dovrebbe essere fatto ed è sbagliato a molti livelli. Tuttavia questo dovrebbe darti un'idea migliore di cosa sto parlando.
Come puoi vedere niente può rompersi:
- Applichiamo una serie di funzioni al nostro valore
- Se in qualsiasi momento il valore diventa nullo (o non definito) semplicemente non applichiamo più alcuna funzione.
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>
Appendice 1
Non riesco a spiegare cosa sono le monadi perché questo non è lo scopo di questo post e ci sono persone là fuori migliori di me in questo. Tuttavia, come ha detto Eric Elliot nel suo post sul blog JavaScript Monads Made Simple :
Indipendentemente dal tuo livello di abilità o dalla comprensione della teoria delle categorie, l'uso delle monadi rende più facile lavorare con il tuo codice. Non riuscire a trarre vantaggio dalle monadi può rendere più difficile lavorare con il codice (ad esempio, callback hell, rami condizionali annidati, più verbosità).
Appendice 2
Ecco come risolverei il tuo problema usando il Forse monade dimonetjs
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..catchistruzione. Detto questo, un array che contiene elementi estremamente eterogenei mi sembra un problema di progettazione.