Уявіть, що ми хочемо застосувати низку функцій до того xчи іншого випадкуx це недійсне значення:
if (x !== null) x = a(x);
if (x !== null) x = b(x);
if (x !== null) x = c(x);
Тепер скажемо, що нам потрібно зробити те саме y :
if (y !== null) y = a(y);
if (y !== null) y = b(y);
if (y !== null) y = c(y);
І те ж саме z :
if (z !== null) z = a(z);
if (z !== null) z = b(z);
if (z !== null) z = c(z);
Як ви можете бачити без належної абстракції, ми зрештою повторюватимемо дублювання коду. Така абстракція вже існує: Монада Можливо .
The Монада Можливо" містить як значення, так і обчислювальний контекст:
- Монада зберігає значення в безпеці і застосовує до нього функції.
- Обчислювальний контекст - це нульова перевірка перед застосуванням функції.
Наївна реалізація виглядала б так:
⚠️ Ця реалізація призначена лише для ілюстрації! Це не так, як це слід робити, і неправильно на багатьох рівнях. Однак це повинно дати вам краще уявлення про те, про що я говорю.
Як бачите, нічого не може зламатися:
- Ми застосовуємо цілий ряд функцій до нашого значення
- Якщо в будь-який момент значення стає нульовим (або невизначеним), ми більше не застосовуємо жодної функції.
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>
Додаток 1
Я не можу пояснити, що таке монади, оскільки це не мета цієї посади, і люди там кращі, ніж я. Однак, як сказав Ерік Елліот у своєму блозі hist Mostov, зроблений простим :
Незалежно від рівня вашої кваліфікації чи розуміння теорії категорій, використання монад полегшує ваш код. Якщо не скористатися монадами, це може ускладнити роботу вашого коду (наприклад, пекельний зворотний виклик, вкладені умовні гілки, більше багатослів’я).
Додаток 2
Ось як я вирішував би ваше питання, використовуючи монаду " Можливо"монети
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..catchзаявити. Однак, масив, який містить дико гетерогенні елементи, виглядає для мене проблемою дизайну.