"إذا أراد العامل أن يؤدي عمله بشكل جيد، فعليه أولاً أن يشحذ أدواته." - كونفوشيوس، "مختارات كونفوشيوس. لو لينجونج"
الصفحة الأمامية > برمجة > مقدمة للبرمجة الوظيفية في JavaScript: monads مختلفة #11

مقدمة للبرمجة الوظيفية في JavaScript: monads مختلفة #11

تم النشر بتاريخ 2024-07-29
تصفح:779

Introduction to Functional Programming in JavaScript: Different monads #11

تعد Monads مفهومًا أساسيًا في البرمجة الوظيفية التي توفر طريقة للتعامل مع الحسابات وتحويلات البيانات بطريقة منظمة. هناك أنواع مختلفة من المونادات، كل منها مصمم لحل مشكلات معينة والتعامل مع أنواع مختلفة من البيانات والتأثيرات.

ما هو الموناد؟

الموناد هو تجريد يسمح بتسلسل العمليات على القيم الملتفة. يتم تعريفه من خلال ثلاث خصائص أساسية:

  1. الوحدة (وتسمى أيضًا أو تعود): دالة تأخذ قيمة وتلفها في أحادي.
  2. Bind (وتسمى أيضًا flatMap أو chain): دالة تأخذ قيمة أحادية ووظيفة تُرجع أحادية، وتطبق الوظيفة على القيمة الملتفة، وترجع أحادية جديدة.
  3. الترابط: يجب أن يكون تكوين العمليات الأحادية ترابطيًا.

الأنواع الشائعة من المونادات

  1. ربما موناد
  2. إما موناد
  3. وعد موناد
  4. قائمة موناد
  5. القارئ موناد
  6. الكاتب موناد
  7. الدولة موناد

1. ربما موناد

يتم استخدام ربما Monad للتعامل مع القيم الاختيارية. إنه يمثل عملية حسابية قد تفشل أو تُرجع فارغة أو غير محددة.

تطبيق
class Maybe {
  constructor(value) {
    this.value = value;
  }

  static of(value) {
    return new Maybe(value);
  }

  isNothing() {
    return this.value === null || this.value === undefined;
  }

  map(fn) {
    return this.isNothing() ? this : Maybe.of(fn(this.value));
  }

  flatMap(fn) {
    return this.isNothing() ? this : fn(this.value);
  }
}

// Usage
const maybeValue = Maybe.of('hello')
  .map(str => str.toUpperCase())
  .flatMap(str => Maybe.of(`${str} WORLD`));
console.log(maybeValue); // Maybe { value: 'HELLO WORLD' }

2. إما موناد

يتم استخدام إما Monad للتعامل مع الحسابات التي يمكن أن تُرجع إما قيمة نجاح (يمين) أو قيمة خطأ (يسار).

تطبيق
class Either {
  constructor(value, isRight = true) {
    this.value = value;
    this.isRight = isRight;
  }

  static right(value) {
    return new Either(value, true);
  }

  static left(value) {
    return new Either(value, false);
  }

  map(fn) {
    return this.isRight ? Either.right(fn(this.value)) : this;
  }

  flatMap(fn) {
    return this.isRight ? fn(this.value) : this;
  }
}

// Usage
const rightValue = Either.right(5)
  .map(x => x   1)
  .flatMap(x => Either.right(x * 2));
console.log(rightValue); // Either { value: 12, isRight: true }

const leftValue = Either.left('error')
  .map(x => x   1)
  .flatMap(x => Either.right(x * 2));
console.log(leftValue); // Either { value: 'error', isRight: false }

3. وعد موناد

يتم استخدام Promise Monad للتعامل مع الحسابات غير المتزامنة.

الاستخدام
const fetchData = url => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(`Data from ${url}`);
    }, 1000);
  });
};

// Usage
fetchData('https://api.example.com')
  .then(data => {
    console.log(data); // 'Data from https://api.example.com'
    return fetchData('https://api.example.com/2');
  })
  .then(data => {
    console.log(data); // 'Data from https://api.example.com/2'
  })
  .catch(error => {
    console.error(error);
  });

4. قائمة موناد

يتم استخدام List Monad للتعامل مع العمليات الحسابية التي تنتج قائمة من القيم.

تطبيق
class List {
  constructor(values) {
    this.values = values;
  }

  static of(values) {
    return new List(values);
  }

  map(fn) {
    return List.of(this.values.map(fn));
  }

  flatMap(fn) {
    return List.of(this.values.flatMap(value => fn(value).values));
  }
}

// Usage
const list = List.of([1, 2, 3])
  .map(x => x   1)
  .flatMap(x => List.of([x, x * 2]));
console.log(list); // List { values: [ 2, 4, 3, 6, 4, 8 ] }

5. القارئ موناد

يتم استخدام Reader Monad للتعامل مع العمليات الحسابية التي تعتمد على بعض البيئات أو التكوينات المشتركة.

تطبيق
class Reader {
  constructor(fn) {
    this.fn = fn;
  }

  static of(value) {
    return new Reader(() => value);
  }

  map(fn) {
    return new Reader(env => fn(this.fn(env)));
  }

  flatMap(fn) {
    return new Reader(env => fn(this.fn(env)).fn(env));
  }

  run(env) {
    return this.fn(env);
  }
}

// Usage
const config = { baseURL: 'https://api.example.com' };

const fetchUser = new Reader(env => `${env.baseURL}/user`);
const fetchPosts = new Reader(env => `${env.baseURL}/posts`);

const fetchUserAndPosts = fetchUser.flatMap(userURL =>
  fetchPosts.map(postsURL => ({ userURL, postsURL }))
);

console.log(fetchUserAndPosts.run(config)); 
// { userURL: 'https://api.example.com/user', postsURL: 'https://api.example.com/posts' }

6. الكاتب موناد

يتم استخدام Writer Monad للتعامل مع الحسابات التي تنتج قيمة مع سجل أو بيانات إضافية.

تطبيق
class Writer {
  constructor(value, log) {
    this.value = value;
    this.log = log;
  }

  static of(value) {
    return new Writer(value, '');
  }

  map(fn) {
    const result = fn(this.value);
    return new Writer(result.value, this.log   result.log);
  }

  flatMap(fn) {
    const result = fn(this.value);
    return new Writer(result.value, this.log   result.log);
  }

  tell(log) {
    return new Writer(this.value, this.log   log);
  }
}

// Usage
const writer = Writer.of(3)
  .map(value => new Writer(value   1, 'Incremented\n'))
  .flatMap(value => new Writer(value * 2, 'Doubled\n'));

console.log(writer); 
// Writer { value: 8, log: 'Incremented\nDoubled\n' }

7. الدولة موناد

يتم استخدام State Monad للتعامل مع الحسابات التي تحافظ على الحالة.

تطبيق
class State {
  constructor(runState) {
    this.runState = runState;
  }

  static of(value) {
    return new State(state => [value, state]);
  }

  map(fn) {
    return new State(state => {
      const [value, newState] = this.runState(state);
      return [fn(value), newState];
    });
  }

  flatMap(fn) {
    return new State(state => {
      const [value, newState] = this.runState(state);
      return fn(value).runState(newState);
    });
  }

  run(initialState) {
    return this.runState(initialState);
  }
}

// Usage
const increment = new State(state => [state   1, state   1]);

const result = increment
  .flatMap(() => increment)
  .flatMap(() => increment)
  .run(0);

console.log(result); // [3, 3]

خاتمة

توفر Monads طريقة منظمة ويمكن التنبؤ بها للتعامل مع الحسابات وتحويلات البيانات في البرمجة الوظيفية. يخدم كل نوع من أنواع الموناد غرضًا محددًا، بدءًا من التعامل مع القيم الاختيارية باستخدام Maybe Monad وحتى إدارة العمليات غير المتزامنة باستخدام Promise Monad.

بيان الافراج تم إعادة إنتاج هذه المقالة على: https://dev.to/francescoagati/introduction-to-functional-programming-in-javascript-different-monads-11-2je1?1 إذا كان هناك أي انتهاك، يرجى الاتصال بـ [email protected] لحذفه
أحدث البرنامج التعليمي أكثر>

تنصل: جميع الموارد المقدمة هي جزئيًا من الإنترنت. إذا كان هناك أي انتهاك لحقوق الطبع والنشر الخاصة بك أو الحقوق والمصالح الأخرى، فيرجى توضيح الأسباب التفصيلية وتقديم دليل على حقوق الطبع والنشر أو الحقوق والمصالح ثم إرسالها إلى البريد الإلكتروني: [email protected]. سوف نتعامل مع الأمر لك في أقرب وقت ممكن.

Copyright© 2022 湘ICP备2022001581号-3