الموناد (البرمجة الوظيفية)
في البرمجة الوظيفية ، تُعدّ المونادات طريقةً لهيكلة العمليات الحسابية كسلسلة من الخطوات، حيث تُنتج كل خطوة قيمةً، بالإضافة إلى بعض المعلومات الإضافية حول العملية الحسابية، مثل احتمال حدوث فشل، أو عدم حتمية، أو تأثير جانبي. وبشكلٍ أكثر دقة، المونادة هي مُنشئ نوع M مُزوّد بعمليتين، الأولى تُحوّل القيمة إلى سياق المونادة، والثانية تربط العمليات الحسابية المونادية. بعبارةٍ أبسط، يُمكن اعتبار المونادات واجهات مُطبّقة على مُنشئات الأنواع، تسمح للدوال بتجريد مُختلف مُتغيرات مُنشئات الأنواع التي تُطبّق المونادة (مثل ، إلخ). [ 1 ] [ 2 ]return:<A>(a:A)->M(A)bind:<A,B>(m_a:M(A),f:A->M(B))->M(B)OptionList
ينبع كل من مفهوم الموناد ومصطلحه في الأصل من نظرية الفئات ، حيث تُعرَّف الموناد بأنها دالة داخلية ذات بنية إضافية. [ أ ] [ ب ] وقد أثبتت الأبحاث التي بدأت في أواخر الثمانينيات وأوائل التسعينيات أن المونادات قادرة على دمج مشاكل علوم الحاسوب التي تبدو متباينة ضمن نموذج وظيفي موحد. كما توفر نظرية الفئات بعض المتطلبات الرسمية، المعروفة بقوانين الموناد ، والتي يجب أن تستوفيها أي موناد، ويمكن استخدامها للتحقق من صحة الشيفرة المونادية. [ 3 ] [ 4 ]
بما أن المونادات تُوضّح دلالات نوعٍ من العمليات الحسابية، فيمكن استخدامها أيضًا لتنفيذ ميزات لغوية ملائمة. بل إن بعض اللغات، مثل هاسكل ، تُقدّم تعريفات مُسبقة في مكتباتها الأساسية لبنية الموناد العامة وحالاتها الشائعة. [ 1 ] [ 5 ]
ملخص
"بالنسبة للموناد m، تمثل قيمة من نوع معين m aإمكانية الوصول إلى قيمة من نوع معين aضمن سياق الموناد." — سي إيه ماكان [ 6 ]
بتعبير أدق، يمكن استخدام الموناد عندما يكون الوصول غير المقيد إلى قيمة ما غير مناسب لأسباب خاصة بالسيناريو. ففي حالة موناد "ربما"، يكون ذلك لأن القيمة قد لا تكون موجودة. أما في حالة موناد الإدخال/الإخراج ، فيكون ذلك لأن القيمة قد لا تكون معروفة بعد، كما هو الحال عندما يمثل الموناد مدخلات المستخدم التي لن تُقدم إلا بعد عرض موجه الأوامر. في جميع الحالات، تُحدد السيناريوهات التي يكون فيها الوصول منطقيًا من خلال عملية الربط المُعرّفة للموناد؛ ففي موناد "ربما"، تُربط القيمة فقط إذا كانت موجودة، وفي موناد الإدخال/الإخراج، تُربط القيمة فقط بعد تنفيذ العمليات السابقة في التسلسل.
يمكن إنشاء الموناد عن طريق تعريف مُنشئ النوع M وعمليتين:
return :: a -> M a(يُطلق عليها غالبًا اسم الوحدة )، والتي تستقبل قيمة من نوع معينaوتُغلّفها في قيمة أحادية من نوع آخرM a، وbind :: (M a) -> (a -> M b) -> (M b)(يُشار إليها عادةً بـ>>=)، والتي تستقبل قيمة أحادية من النوعM aودالةfتقبل قيمًا من النوع الأساسيa. تقوم الدالة Bind بفك تغليفM a، وتطبيقهاfعليها، ويمكنها معالجة نتيجةfكقيمة أحاديةM b.
( يمكن إيجاد بنية بديلة ولكنها مكافئة باستخدام الدالة join بدلاً من المؤثر في القسم اللاحق § الاشتقاق من الدوال .)bind
باستخدام هذه العناصر، يُنشئ المبرمج سلسلة من استدعاءات الدوال (خط أنابيب) مع عدة عوامل ربط متصلة معًا في تعبير. يُحوّل كل استدعاء دالة قيمة الإدخال من النوع العادي، ويتعامل عامل الربط مع القيمة الأحادية المُعادة، والتي تُمرر إلى الخطوة التالية في السلسلة.
عادةً، قد يحتوي عامل الربط >>=على شيفرة خاصة بالموناد تُنفّذ خطوات حسابية إضافية غير متوفرة في الدالة المُستلمة كمعامل. بين كل زوج من استدعاءات الدوال المُركّبة، يُمكن لعامل الربط إدخال m aمعلومات إضافية غير متاحة داخل الدالة في قيمة الموناد f، وتمريرها عبر مسار المعالجة. كما يُمكنه التحكم بشكل أدق في سير التنفيذ، على سبيل المثال عن طريق استدعاء الدالة فقط في ظل شروط مُحددة، أو تنفيذ استدعاءات الدوال بترتيب مُعين.
مثال: ربما
أحد الأمثلة على الموناد هو Maybeالنوع. تُعدّ النتائج الفارغة غير المُعرّفة إحدى المشكلات الرئيسية التي لا توفر العديد من لغات البرمجة الإجرائية أدوات مُحددة للتعامل معها، مما يستلزم استخدام نمط الكائن الفارغ أو عمليات التحقق لاختبار القيم غير الصالحة في كل عملية لمعالجة القيم غير المُعرّفة. يتسبب هذا في ظهور أخطاء برمجية ويُصعّب بناء برامج قوية تتعامل مع الأخطاء بسلاسة. Maybeيُجبر النوع المبرمج على التعامل مع هذه النتائج التي قد تكون غير مُعرّفة من خلال تحديد حالتي النتيجة بشكل صريح: فارغة Just ⌑result⌑أو غير فارغة Nothing. على سبيل المثال، قد يقوم المبرمج بإنشاء مُحلّل لغوي، والذي يُفترض أن يُعيد نتيجة وسيطة، أو يُشير إلى حالة اكتشفها المُحلّل اللغوي، والتي يجب على المبرمج معالجتها أيضًا. مع إضافة بعض الوظائف الإضافية، Maybeيتحول هذا النوع إلى موناد كاملة الميزات. [ ج ] : 12.3، الصفحات 148-151
في معظم لغات البرمجة، يُعرف موناد Maybe أيضًا باسم نوع الخيار ، وهو نوع يُحدد ما إذا كان يحتوي على قيمة أم لا. عادةً ما يُعبَّر عنه كنوع مُعدَّد . في لغة برمجة Rust ، يُسمى Option<T>هذا النوع، ويمكن أن تكون متغيراته إما قيمة من نوع عامT ، أو النوع الفارغ None.
// يُمثل <T> نوعًا عامًا من نوع "T " enum Option <T> { Some ( T ) , None , }Option<T>يمكن فهمها أيضًا على أنها نوع "تغليف"، وهنا تكمن صلتها بالمونادات. في اللغات التي تحتوي على شكل من أشكال نوع Maybe، توجد وظائف تساعد في استخدامها مثل تركيب الدوال المونادية مع بعضها البعض واختبار ما إذا كان Maybe يحتوي على قيمة.
في المثال التالي المبرمج مسبقًا، يتم استخدام نوع Maybe كنتيجة للوظائف التي قد تفشل، وفي هذه الحالة لا يُرجع النوع أي شيء إذا كان هناك قسمة على صفر .
دالة القسمة ( x : عدد عشري ، y : عدد عشري ) -> خيار < عدد عشري > { إذا كان y يساوي 0 { لا شيء } وإلا { بعض ( x / y ) } } // القسمة(1.0، 4.0) -> تُرجع بعض(0.25) // القسمة(3.0، 0.0) -> تُرجع لا شيءإحدى هذه الطرق لاختبار ما إذا كان المتغير Maybe يحتوي على قيمة أم لا هي استخدام ifالعبارات.
let m_x = divide ( 3.14 , 0.0 ); // انظر دالة القسمة أعلاه // تستخرج عبارة if قيمة x من m_x إذا كانت m_x هي صيغة Just من Maybe if let Some ( x ) = m_x { println! ( "الجواب: {}" , x ); } else { println! ( "فشلت القسمة، خطأ في القسمة على صفر..." ); }قد تحتوي لغات أخرى على مطابقة الأنماط
let result = divide ( 3.0 , 2.0 ); match result { Some ( x ) => println! ( "الإجابة: {}" , x ), None => println! ( "فشلت عملية القسمة؛ سننجح في المرة القادمة." ), }يمكن للمونادات أن تُركّب دوالًا تُرجع قيمة من نوع Maybe، وذلك بدمجها معًا. على سبيل المثال، قد تأخذ دالة واحدة عدة مُعاملات من نوع Maybe، وتُرجع قيمة واحدة من نوع Maybe تكون قيمتها Nothing عندما تكون أي من المُعاملات Nothing، كما في المثال التالي:
fn chainable_division ( maybe_x : Option < Decimal > , maybe_y : Option < Decimal > ) -> Option < Decimal > { let x = maybe_x ? ; let y = maybe_y ? ;// إذا كانت كلتا المدخلتين غير None، // تحقق من القسمة على صفر واقسم وفقًا لذلك // وإلا، أرجع None إذا كانت y == 0 { None } else { Some ( x / y ) } } chainable_division ( chainable_division ( Some ( 2.0 ), Some ( 0.0 )), Some ( 1.0 )); // داخل chainable_division يفشل، خارج chainable_division يُرجع None بدلاً من تكرار Someالتعبيرات، يمكننا استخدام ما يُسمى عامل الربط (المعروف أيضاً باسم "map" أو "flatmap" أو "shove" [ 8 ] : 2205 ). تأخذ هذه العملية موناداً ودالةً تُعيد موناداً، وتُنفّذ الدالة على القيمة الداخلية للموناد المُمرَّر، ثم تُعيد الموناد من الدالة.
// مثال بلغة Rust باستخدام ".map". يتم تمرير maybe_x عبر دالتين تُرجعان Decimal وString على التوالي. // كما هو الحال مع تركيب الدوال العادي، يجب أن تتطابق مدخلات ومخرجات الدوال التي تغذي بعضها البعض مع الأنواع المُغلّفة. (أي يجب أن تُرجع الدالة add_one قيمة Decimal والتي يمكن تمريرها بعد ذلك إلى الدالة decimal_to_string) let maybe_x : Option < Decimal > = Some ( 1.0 ); let maybe_result = maybe_x . map ( add_one ). map ( decimal_to_string );في لغة هاسكل، يوجد مُعامل ربط ( >>=) يسمح بهذا التركيب الأحادي بشكل أكثر أناقة يُشبه تركيب الدوال . [ د ] : 150-151
halve :: Int -> Maybe Int halve x | even x = Just ( x ` div ` 2 ) | odd x = Nothing -- هذا الكود يُنصف x مرتين. يُقيّم إلى Nothing إذا لم يكن x من مضاعفات 4 halve x >>= halveباستخدام >>=الدالة `available`، chainable_divisionيمكن التعبير عن ذلك بإيجاز أكبر بكثير بمساعدة الدوال المجهولة (أي دوال لامدا). لاحظ في التعبير أدناه كيف تعمل كل من دالتي لامدا المتداخلتين على القيمة المُغلّفة في Maybeالموناد المُمرّر باستخدام عامل الربط. [ e ] : 93
chainable_division ( mx , my ) = mx >>= ( λx -> my >>= ( λy -> Just ( x / y ) ) )ما تم عرضه حتى الآن هو في الأساس موناد، ولكن لكي نكون أكثر إيجازًا، فإن ما يلي هو قائمة صارمة بالصفات الضرورية للموناد كما هو محدد في القسم التالي.
- النمط الأحادي
- النوع (
Maybe) [ ج ] : 148–151 - عملية الوحدة
- محول نوع (
Just(x)) [ هـ ] : 93 - عملية الربط
- مُركِّب للدوال الأحادية (
>>=أو.flatMap()) [ د ] : 150-151
هذه هي العناصر الثلاثة اللازمة لتكوين الموناد. قد تجسد المونادات الأخرى عمليات منطقية مختلفة، وقد يمتلك بعضها خصائص إضافية، لكن جميعها ستشترك في هذه المكونات الثلاثة المتشابهة. [ 1 ] [ 9 ]
تعريف
يعتمد التعريف الأكثر شيوعًا للموناد في البرمجة الوظيفية، والمستخدم في المثال أعلاه، على ثلاثية كليسلي ⟨T, η, μ⟩ وليس على التعريف القياسي لنظرية الفئات. ومع ذلك، يتضح أن البنيتين متكافئتان رياضيًا، لذا فإن أيًا من التعريفين سينتج مونادًا صحيحًا. وبالنظر إلى أي نوعين أساسيين محددين جيدًا T و U ، يتكون الموناد من ثلاثة أجزاء:
- مُنشئ نوع M الذي يُنشئ نوعًا أحاديًا MT [ f ]
- محول نوع ، يُطلق عليه غالبًا اسم الوحدة أو الإرجاع ، يقوم بتضمين كائن x في الموناد:
unit : T → M T[ ز ] - المُركِّب ، الذي يُسمى عادةً bind ( كما في ربط متغير ) ويتم تمثيله بواسطة عامل infix
>>=أو طريقة تسمى flatMap ، يقوم بفك تغليف متغير أحادي، ثم يُدرجه في دالة/تعبير أحادي، مما ينتج عنه قيمة أحادية جديدة:
ولكن لكي تُعتبر هذه الأجزاء الثلاثة مونادًا بشكل كامل، يجب عليها أيضًا أن تحترم بعض القوانين:
- الوحدة هي عنصر محايد يساري للربط :
unit(x) >>= f↔f(x) - الوحدة هي أيضًا هوية يمنى للربط :
ma >>= unit↔ma - الربط هو في الأساس ترابطي : [ i ]
جبريًا، هذا يعني أن أي موناد يؤدي إلى فئة (تسمى فئة كليسلي ) و مونويد في فئة الدوال (من القيم إلى الحسابات)، مع التركيب المونادي كمؤثر ثنائي في المونويد [ 8 ] : 2450s والوحدة كعنصر هوية في المونويد.
الاستخدام
تتجاوز قيمة نمط الموناد مجرد تكثيف الكود وتوفير رابط للاستدلال الرياضي. بغض النظر عن لغة البرمجة أو نموذج البرمجة الافتراضي الذي يستخدمه المطور، فإن اتباع نمط الموناد يُحقق العديد من مزايا البرمجة الوظيفية البحتة . من خلال تجسيد نوع محدد من العمليات الحسابية، لا يقتصر دور الموناد على تغليف التفاصيل الدقيقة لهذا النمط الحسابي فحسب، بل يفعل ذلك بطريقة تصريحية ، مما يُحسّن وضوح الكود. ولأن قيم الموناد تُمثل بشكل صريح ليس فقط القيم المحسوبة، بل التأثيرات المحسوبة أيضًا ، يُمكن استبدال تعبير الموناد بقيمته في مواضع شفافة مرجعيًا ، تمامًا كما هو الحال مع التعبيرات البحتة، مما يسمح بالعديد من التقنيات والتحسينات القائمة على إعادة الكتابة . [ 4 ]
عادةً ما يستخدم المبرمجون دالة الربط (bind) لربط الدوال الأحادية في تسلسل، مما دفع البعض إلى وصف الأحاديات بأنها "فواصل منقوطة قابلة للبرمجة"، في إشارة إلى استخدام العديد من لغات البرمجة الإجرائية للفواصل المنقوطة لفصل التعليمات . [ 1 ] [ 5 ] مع ذلك، لا تُرتّب الأحاديات العمليات الحسابية فعليًا؛ فحتى في اللغات التي تستخدمها كميزات أساسية، يمكن لتركيب الدوال الأبسط ترتيب الخطوات داخل البرنامج. تكمن فائدة الأحاديات العامة في تبسيط بنية البرنامج وتحسين فصل الاهتمامات من خلال التجريد. [ 4 ] [ 11 ]
يمكن اعتبار بنية الموناد شكلاً رياضياً فريداً، ونمطاً خاصاً بوقت الترجمة ، لنمط الديكور . بعض المونادات قادرة على تمرير بيانات إضافية لا يمكن للدوال الوصول إليها، بل إن بعضها الآخر يفرض تحكماً أدق في التنفيذ، كاستدعاء دالة معينة فقط في ظروف محددة. ولأنها تتيح لمبرمجي التطبيقات تنفيذ منطق المجال مع نقل الشيفرة النمطية إلى وحدات مُطوَّرة مسبقاً، يمكن اعتبار المونادات أداةً للبرمجة الموجهة نحو الجوانب . [ 12 ]
من الاستخدامات الأخرى الجديرة بالذكر للمونادات عزل الآثار الجانبية، مثل الإدخال/الإخراج أو الحالة القابلة للتغيير ، في الشيفرة الوظيفية البحتة. حتى اللغات الوظيفية البحتة يمكنها تنفيذ هذه العمليات الحسابية "غير النقية" بدون مونادات، وذلك عبر مزيج معقد من تركيب الدوال وأسلوب تمرير الاستمرارية (CPS) على وجه الخصوص. [ 2 ] مع المونادات، يمكن تجريد جزء كبير من هذا الهيكل، وذلك أساسًا عن طريق أخذ كل نمط متكرر في شيفرة CPS وتجميعه في مونادة منفصلة. [ 4 ]
إذا لم تدعم لغة البرمجة المونادات افتراضيًا، فلا يزال من الممكن تطبيق هذا النمط، غالبًا دون صعوبة كبيرة. عند ترجمة مفهوم الموناد من نظرية الفئات إلى مصطلحات البرمجة، يصبح مفهومًا عامًا ويمكن تعريفه مباشرةً في أي لغة تدعم ميزة مكافئة للتعددية المحدودة . إن قدرة المفهوم على البقاء غير متأثر بالتفاصيل التشغيلية أثناء العمل على الأنواع الأساسية ميزة قوية، لكن الخصائص الفريدة والسلوك الصارم للمونادات يميزها عن المفاهيم الأخرى. [ 13 ]
التطبيقات
عادةً ما تركز المناقشات حول المونادات المحددة على حل مشكلة تنفيذية ضيقة، لأن كل موناد يمثل شكلاً حسابياً محدداً. مع ذلك، في بعض الحالات، يمكن للتطبيق أن يحقق أهدافه العامة باستخدام مونادات مناسبة ضمن منطقه الأساسي.
فيما يلي بعض التطبيقات التي تتخذ من المونادات محوراً أساسياً في تصميماتها:
- تستخدم مكتبة محلل Parsec المونادات لدمج قواعد التحليل الأبسط في قواعد أكثر تعقيدًا، وهي مفيدة بشكل خاص للغات ذات النطاق المحدد الأصغر . [ 14 ]
- xmonad هو مدير نوافذ متجانب يتمحور حول بنية بيانات السحاب ، والتي يمكن التعامل معها بشكل أحادي كحالة خاصة من الاستمراريات المحددة . [ 15 ]
- توفر LINQ من مايكروسوفت لغة استعلام لإطار عمل .NET تتأثر بشكل كبير بمفاهيم البرمجة الوظيفية، بما في ذلك عوامل التشغيل الأساسية لتكوين الاستعلامات بشكل أحادي. [ 16 ]
- ZipperFS هو نظام ملفات تجريبي بسيط يستخدم بنية السحاب بشكل أساسي لتنفيذ ميزاته. [ 17 ]
- يوفر إطار عمل الإضافات التفاعلية بشكل أساسي واجهة (مشتركة) أحادية لتدفقات البيانات التي تحقق نمط المراقب . [ 18 ]
تاريخ
يعود مصطلح "موناد" في البرمجة إلى لغتي البرمجة APL و J ، اللتين تميلان إلى أن تكونا وظيفيتين بحتتين. مع ذلك، في هاتين اللغتين، "موناد" هو اختصار فقط لدالة تأخذ مُعاملًا واحدًا (الدالة التي تأخذ مُعاملين تُسمى "داياد"، وهكذا). [ 19 ]
كان عالم الرياضيات روجر غودمان أول من صاغ مفهوم الموناد (وأطلق عليه اسم "البنية القياسية") في أواخر خمسينيات القرن العشرين، على الرغم من أن مصطلح "الموناد" الذي شاع استخدامه لاحقًا قد شاع بفضل عالم نظرية الفئات سوندرز ماك لين . أما الصيغة المحددة أعلاه باستخدام bind ، فقد وصفها عالم الرياضيات هاينريش كلايسلي في الأصل عام 1965 لإثبات أن أي موناد يمكن وصفه بأنه اقتران بين دالتين (متغايرتين). [ 20 ]
ابتداءً من ثمانينيات القرن العشرين، بدأت فكرة غامضة عن نمط الموناد بالظهور في أوساط علوم الحاسوب. ووفقًا لباحث لغات البرمجة فيليب وادلر ، فقد تنبأ عالم الحاسوب جون سي. رينولدز بالعديد من جوانبه في سبعينيات القرن العشرين وأوائل ثمانينياته، عندما ناقش أهمية أسلوب تمرير الاستمرارية ، ونظرية الفئات كمصدر غني للدلالات الرسمية، والتمييز بين القيم والحسابات. [ 4 ] كما اعتمدت لغة البحث أوبال ، التي صُممت بنشاط حتى عام 1990، بشكل فعال على نوع الموناد في عمليات الإدخال والإخراج، ولكن لم يُدرك هذا الربط في ذلك الوقت. [ 21 ]
كان عالم الحاسوب يوجينيو موجي أول من ربط صراحةً بين مفهوم الموناد في نظرية الفئات والبرمجة الوظيفية، وذلك في ورقة بحثية قُدّمت في مؤتمر عام 1989، [ 22 ] تلتها ورقة بحثية أكثر دقة نُشرت في مجلة علمية عام 1991. في أعمال سابقة، طوّر العديد من علماء الحاسوب استخدام نظرية الفئات لتوفير دلالات لحساب لامدا . تمثّلت رؤية موجي الأساسية في أن البرنامج الواقعي ليس مجرد دالة من قيم إلى أخرى، بل هو تحويل يُشكّل عمليات حسابية على تلك القيم. عند صياغة ذلك بمصطلحات نظرية الفئات، يُستنتج أن المونادات هي البنية المناسبة لتمثيل هذه العمليات الحسابية. [ 3 ]
قام العديد من الباحثين بنشر هذه الفكرة وتطويرها، بمن فيهم فيليب وادلر وسيمون بيتون جونز ، وكلاهما شارك في تحديد مواصفات لغة هاسكل. استخدمت هاسكل نموذج "التدفق الكسول" الإشكالي حتى الإصدار 1.2 للتوفيق بين الإدخال والإخراج والتقييم الكسول ، إلى أن تحولت إلى واجهة أحادية أكثر مرونة. [ 23 ] واصل مجتمع هاسكل تطبيق المونادات على العديد من مشاكل البرمجة الوظيفية، وفي العقد الثاني من الألفية الثانية، أدرك الباحثون العاملون مع هاسكل أن المونادات هي دوال تطبيقية ؛ [ 24 ] [ j ] وأن كلاً من المونادات والأسهم هي أحاديات . [ 26 ]
في البداية، اقتصر استخدام البرمجة باستخدام المونادات في الغالب على لغة هاسكل ومشتقاتها، ولكن مع تأثير البرمجة الوظيفية على نماذج برمجية أخرى، تبنت العديد من اللغات نمط المونادات (بشكل أساسي وإن لم يكن رسميًا). توجد الآن صيغ لهذا النمط في لغات مثل سكيم ، وبيرل ، وبايثون ، وراكيت ، وكلوجر ، وسكالا ، وإف شارب ، كما تم النظر في إدراجه ضمن معيار جديد للغة ML .
تحليل
تتمثل إحدى مزايا نمط الموناد في إضفاء دقة رياضية على تركيب العمليات الحسابية. يمكن استخدام قوانين الموناد للتحقق من صحة حالة معينة، بالإضافة إلى إمكانية استخدام خصائص من هياكل ذات صلة (مثل الدوال) من خلال التنميط الفرعي .
التحقق من قوانين الموناد
بالعودة إلى Maybeالمثال، تم الإعلان عن مكوناته لتشكل موناد، ولكن لم يتم تقديم أي دليل على أنها تفي بقوانين الموناد.
يمكن تصحيح ذلك عن طريق إدخال تفاصيل محددة Maybeفي أحد جانبي القوانين العامة، ثم بناء سلسلة من المعادلات جبريًا للوصول إلى الجانب الآخر:
القانون 1: η(a) >>= f(x) ⇔ (فقط a) >>= f(x) ⇔ f(a)
القانون الثاني: ma >>= eta(x) ⇔ ma إذا كانت ma تساوي (فقط a) ، فإن eta(a) ⇔ فقط a، وإلا أو Nothing ⇔ لا شيء .
القانون 3: ( ma >>= f(x) ) >>= g(y) ⇔ ma >>= ( f(x) >>= g(y) )إذا كان (ma >>= f(x)) يساوي (فقط b) ، فإذا كان ma يساوي (فقط a) ، فإن g(ma >>= f(x)) (f(x) >>= g(y)) يساوي a ، وإلا فلا شيء . ⇔ إذا كانت ma تساوي (فقط a) و f(a) تساوي (فقط b) ، فإن (g ∘ f) a، وإذا كانت ma تساوي (فقط a) و f(a) تساوي لا شيء ، فلا شيء ، وإلا فلا شيء .
الاشتقاق من الدوال
على الرغم من ندرة استخدامها في علوم الحاسوب، إلا أنه يمكن استخدام نظرية الفئات مباشرةً، والتي تُعرّف الموناد على أنها دالة مع تحويلين طبيعيين إضافيين . [ ك ] لذا، بدايةً، يتطلب أي هيكل دالة من الرتبة العليا (أو "دالة وظيفية") تُسمى الخريطة لكي يُعتبر دالة:
map : (a → b) → (ma → mb)لكن هذه ليست مشكلة كبيرة دائمًا، خاصةً عندما تُشتق الموناد من دالة موجودة مسبقًا، حيث ترث الموناد دالة map تلقائيًا. (لأسباب تاريخية، mapيُطلق على هذا fmapفي لغة هاسكل اسم map).
التحويل الأول للموناد هو في الواقع نفس الوحدة من ثلاثية كليسلي، ولكن باتباع التسلسل الهرمي للهياكل بدقة، يتضح أن الوحدة تميز الدالة التطبيقية ، وهي بنية وسيطة بين الموناد والدالة الأساسية. في السياق التطبيقي، يُشار إلى الوحدة أحيانًا بأنها نقية ، لكنها لا تزال نفس الدالة. ما يختلف في هذا البناء هو القانون الذي يجب أن تحققه الوحدة ؛ ولأن الربط غير مُعرَّف، يُعطى القيد بدلالة الخريطة بدلاً من ذلك.
(unit ∘ φ) x ↔ ((map φ) ∘ unit) x ↔ x[ 27 ]وتأتي القفزة الأخيرة من الدالة التطبيقية إلى الموناد مع التحويل الثاني، وهو دالة الربط (في نظرية الفئات، هذا تحويل طبيعي يسمى عادةً μ )، والذي "يبسط" التطبيقات المتداخلة للموناد:
join(mma) : M (M T) → M Tوباعتبارها الدالة المميزة، يجب أن تستوفي عملية الربط أيضًا ثلاثة اختلافات في قوانين الموناد:
(join ∘ (map join)) mmma ↔ (join ∘ join) mmma ↔ ma(join ∘ (map unit)) ma ↔ (join ∘ unit) ma ↔ ma(join ∘ (map map φ)) mma ↔ ((map φ) ∘ join) mma ↔ mbبغض النظر عما إذا كان المطور يُعرّف موناد مباشر أو ثلاثية كليسلي، فإن البنية الأساسية ستكون هي نفسها، ويمكن اشتقاق الأشكال من بعضها البعض بسهولة:
(map φ) ma ↔ ma >>= (unit ∘ φ)join(mma) ↔ mma >>= idma >>= f ↔ (join ∘ (map f)) ma[ 28 ]مثال آخر: قائمة
يُظهر موناد القائمة بوضوح كيف يمكن أن يكون اشتقاق موناد من دالة أبسط مفيدًا. في العديد من اللغات، تأتي بنية القائمة مُعرّفة مسبقًا مع بعض الميزات الأساسية، لذا يُفترض Listوجود مُنشئ نوع وعامل إلحاق (مُمثَّل بـ ++للصيغة الوسطية) مُسبقًا هنا.
يُعد تضمين قيمة بسيطة في قائمة أمرًا بسيطًا أيضًا في معظم اللغات:
الوحدة(س) = [س]
من هنا، قد يبدو تطبيق دالة بشكل تكراري باستخدام بناء قائمة خيارًا سهلاً لربط الدوال وتحويل القوائم إلى موناد كامل. تكمن صعوبة هذا الأسلوب في أن دالة الربط تتوقع دوالًا مونادية، والتي ستُخرج في هذه الحالة قوائم بحد ذاتها؛ ومع تطبيق المزيد من الدوال، ستتراكم طبقات من القوائم المتداخلة، مما يتطلب أكثر من مجرد بناء بسيط.
ومع ذلك، فإن إجراء تطبيق أي دالة بسيطة على القائمة بأكملها، أو بعبارة أخرى، تطبيق دالة map ، هو إجراء مباشر:
(الخريطة φ) xlist = [ φ(x1), φ(x2), ..., φ(xn) ]
الآن، هاتان العمليتان تُؤديان بالفعل Listإلى دالة تطبيقية. لكي تُعتبر مونادًا بشكل كامل، يكفي وجود مفهوم صحيح لعملية الربط لتسطيح البنية المتكررة، ولكن بالنسبة للقوائم، فإن ذلك يعني ببساطة فك غلاف قائمة خارجية لإلحاق القوائم الداخلية التي تحتوي على القيم.
join(xlistlist) = join([xlist1, xlist2, ..., xlistn]) = xlist1 ++ xlist2 ++ ... ++ xlistn
لا يقتصر الموناد الناتج على كونه قائمة فحسب، بل هو قائمة تُعيد تحجيم نفسها وتُكثّفها تلقائيًا عند تطبيق الدوال. ويمكن الآن اشتقاق دالة bindList باستخدام صيغة فقط، ثم استخدامها لتمرير القيم عبر سلسلة من الدوال المونادية.

Listأن تبسط بشكل كبير استخدام الدوال متعددة القيم، مثل الجذور المركبة. [ 29 ](xlist >>= f) = join ∘ (map f) xlist
يُستخدم هذا النوع من القوائم الأحادية في تمثيل العمليات الحسابية غير الحتمية . Listإذ يمكنها استيعاب نتائج جميع مسارات التنفيذ في الخوارزمية، ثم اختزال نفسها في كل خطوة لتتجاهل المسارات التي أدت إلى كل نتيجة (وهو فرق جوهري أحيانًا عن الخوارزميات الحتمية الشاملة). ومن فوائدها الأخرى إمكانية تضمين عمليات التحقق في القائمة الأحادية؛ حيث يمكن حذف مسارات محددة بشفافية عند أول نقطة فشل، دون الحاجة إلى إعادة كتابة الدوال في مسار المعالجة. [ 28 ]
تتجلى براعة هذه الطريقة في حالة أخرى ، Listوهي تركيب الدوال متعددة القيم . على سبيل المثال، يجب أن ينتج عن الجذر المركب النوني لعدد ما n عددًا مركبًا مختلفًا، ولكن إذا تم حساب جذر آخر من الرتبة m لهذه النتائج، فيجب أن تكون قيم m×n النهائية مطابقة لمخرجات الجذر m×n . تعمل هذه الطريقة على أتمتة هذه المشكلة تمامًا، حيث تُكثّف النتائج من كل خطوة في قائمة مُسطّحة وصحيحة رياضيًا. [ 29 ]List
التقنيات
تُتيح المونادات فرصًا لتقنيات مثيرة للاهتمام تتجاوز مجرد تنظيم منطق البرنامج. إذ يمكن للمونادات أن تُرسّخ الأساس لميزات نحوية مفيدة، بينما تُمكّن طبيعتها الرياضية عالية المستوى من تحقيق تجريد كبير.
سكر تركيبيلا تدون
على الرغم من أن استخدام bind بشكل صريح غالبًا ما يكون منطقيًا، إلا أن العديد من المبرمجين يفضلون صيغة تحاكي العبارات الإجرائية (تُسمى do-notation في Haskell، وperform-notation في OCaml ، وتعبيرات حسابية في F# ، [ 30 ] و for comprehension في Scala ). هذه مجرد تبسيطات برمجية تُخفي مسارًا أحاديًا على هيئة كتلة برمجية ؛ ثم يقوم المترجم تلقائيًا بترجمة هذه التعبيرات إلى كود وظيفي أساسي.
يمكن أن يُظهر ترجمة addالدالة من لغة البرمجة الأصلية Maybeإلى لغة هاسكل هذه الميزة عمليًا. تبدو النسخة غير الأحادية من الدالة addفي هاسكل كما يلي:
أضف mx my = حالة mx من لا شيء -> لا شيء فقط x -> حالة my من لا شيء -> لا شيء فقط y -> فقط ( x + y )في لغة هاسكل أحادية، returnيُعدّ الاسم القياسي للوحدة ، بالإضافة إلى أنه يجب التعامل مع تعبيرات لامدا بشكل صريح، ولكن حتى مع هذه التفاصيل التقنية، فإن Maybeالموناد يوفر تعريفًا أنظف:
أضف mx my = mx >>= ( \ x -> my >>= ( \ y -> return ( x + y )))لكن باستخدام تدوين "do"، يمكن اختزال هذا الأمر بشكل أكبر إلى تسلسل بديهي للغاية:
أضف mx إلى my = do x <- mx y <- my return ( x + y )يوضح مثال ثانٍ كيفية Maybeاستخدام ذلك في لغة مختلفة تمامًا: F#. باستخدام تعابير الحساب، يمكن كتابة دالة "القسمة الآمنة" التي تُرجع Noneقيمة صحيحة في حالة المعامل غير المُعرَّف أو القسمة على صفر على النحو التالي:
let readNum ( ) = let s = Console.ReadLine ( ) let succ , v = Int32.TryParse ( s ) if ( succ ) then Some ( v ) else Nonelet secure_div = maybe { let ! x = readNum () let ! y = readNum () if ( y = 0 ) then None else return ( x / y ) }أثناء عملية البناء، سيقوم المترجم داخليًا "بإزالة التبسيط" من هذه الدالة إلى سلسلة أكثر كثافة من استدعاءات الربط :
ربما . تأخير ( دالة () -> ربما . ربط ( قراءة الرقم () ، دالة س -> ربما . ربط ( قراءة الرقم () ، دالة ص -> إذا ( ص = 0 ) إذن لا شيء ، وإلا ربما . إرجاع ( س / ص ))))كمثال أخير، يمكن التعبير عن قوانين الموناد العامة نفسها باستخدام تدوين do:
do { x <- return v ; f x } == do { f v } do { x <- m ; return x } == do { m } do { y <- do { x <- m ; f x }; g y } == do { x <- m ; y <- f x ; g y }واجهة عامة
يحتاج كل موناد إلى تطبيق خاص يفي بقوانين الموناد، لكن جوانب أخرى، مثل العلاقة مع البنى الأخرى أو المصطلحات القياسية داخل اللغة، مشتركة بين جميع المونادات. ونتيجة لذلك، قد توفر اللغة أو المكتبة Monadواجهة عامة تتضمن نماذج أولية للدوال ، وعلاقات التفرع، وغيرها من الحقائق العامة. إلى جانب توفير بداية قوية للتطوير وضمان وراثة الموناد الجديد لميزات من نوع أساسي (مثل الدوال)، فإن التحقق من تصميم الموناد مقابل الواجهة يضيف طبقة أخرى من مراقبة الجودة.
المشغلون
يمكن تبسيط الشيفرة الأحادية بشكل أكبر من خلال الاستخدام الأمثل للمعاملات. تُعدّ دالة map مفيدة بشكل خاص لأنها لا تقتصر على الدوال الأحادية المخصصة فقط؛ فما دام من المفترض أن تعمل الدالة الأحادية بشكل مشابه لمعامل مُعرّف مسبقًا، يُمكن استخدام map لتحويل المعامل الأبسط إلى معامل أحادي على الفور. [ l ] باستخدام هذه التقنية، يُمكن تلخيص تعريف addمن المثال في:Maybe
add(mx,my) = map (+)
يمكن تطوير هذه العملية خطوةً أخرى بتحديد addليس فقط لـ Maybe، بل للواجهة بأكملها Monad. وبذلك، سيرث أي موناد جديد يطابق واجهة البنية ويُنفذ خريطتهadd الخاصة نسخةً مُعدّلةً من أيضًا. التغيير الوحيد المطلوب في الدالة هو تعميم توقيع النوع.
أضف : (رقم الموناد، رقم الموناد) → رقم الموناد [ 31 ]
هناك عامل أحادي آخر مفيد أيضًا للتحليل وهو التركيب الأحادي (الممثل >=>هنا بالصيغة infix)، والذي يسمح بتسلسل الدوال الأحادية بأسلوب رياضي أكثر:
(f ≥ g)(x) = f(x) >>= g
باستخدام هذا العامل، يمكن كتابة قوانين الموناد بدلالة الدوال فقط، مما يسلط الضوء على التوافق مع التجميعية ووجود الهوية:
(الوحدة >=> غرام) ↔ غرام (f >=> الوحدة) ↔ f (f >=> g) >=> h ↔ f >=> (g >=> h) [ 1 ]
وبالتالي، يوضح ما سبق معنى كتلة "do" في لغة هاسكل:
يفعل _p <- f(x) _q <- g(_p) h(_q) ↔ ( f >=> g >=> h )(x)
أمثلة أخرى
موناد الهوية
أبسط أنواع الموناد هو موناد الهوية ، الذي يقوم فقط بتعليق القيم والوظائف البسيطة لتلبية قوانين الموناد:
معرف النوع الجديد T = T الوحدة(س) = س (x >>= f) = f(x)
Identityلكن لها استخدامات صحيحة بالفعل، مثل توفير حالة أساسية لمُحوِّلات الموناد التكرارية . كما يمكن استخدامها لإجراء تعيينات المتغيرات الأساسية داخل كتلة برمجية ذات نمط إجرائي. [ م ]
المجموعات
أي مجموعة تحتوي على دالة إلحاق مناسبة تُعتبر أحادية، ولكن اتضح أنها ليست المجموعةList الوحيدة التي تحتوي أيضًا على دالة ربط مُعرّفة جيدًا وتُصنّف كأحادية. بل يمكن تحويلها إلى مجموعات أحادية أخرى ببساطة عن طريق فرض خصائص خاصة على دالة الإلحاق : [ n ] [ o ]List
| مجموعة | خاصية المونويد | الخصائص التوافقية | |||
|---|---|---|---|---|---|
| خاصية التبديل؟ | هل هو متكرر التأثير؟ | تفاصيل | هل تم الطلب؟ | قطع فريدة؟ | |
| قائمة | لا | لا | أحادي حر | نعم | لا |
| مجموعة متعددة منتهية | نعم | لا | لا | لا | |
| مجموعة منتهية | نعم | نعم | لا | نعم | |
موناد الإدخال/الإخراج (هاسكل)
كما ذُكر سابقًا، لا ينبغي أن يحتوي الكود النقي على آثار جانبية غير مُدارة، لكن هذا لا يمنع البرنامج من وصف الآثار وإدارتها بشكل صريح . هذه الفكرة أساسية في موناد الإدخال/الإخراج في لغة هاسكل ، حيث يُمكن اعتبار كائن من نوع معين IO aبمثابة وصف لإجراء يُنفذ في العالم، مع إمكانية توفير معلومات حول العالم من نوع آخر a. الإجراء الذي لا يُوفر أي معلومات عن العالم يكون من النوع IO ()، ويُوفر القيمة الوهمية (). عندما يربط المبرمج IOقيمة بدالة، تحسب هذه الدالة الإجراء التالي بناءً على المعلومات المُقدمة من الإجراء السابق حول العالم (مدخلات من المستخدمين، ملفات، إلخ). [ 23 ] والأهم من ذلك، نظرًا لأنه لا يُمكن ربط قيمة موناد الإدخال/الإخراج إلا بدالة تحسب موناد إدخال/إخراج آخر، فإن دالة الربط تفرض نظامًا لتسلسل الإجراءات، حيث لا يُمكن توفير نتيجة أي إجراء إلا لدالة ستحسب الإجراء التالي. وهذا يعني أن الإجراءات التي لا تحتاج إلى تنفيذ لا يتم تنفيذها أبدًا، والإجراءات التي تحتاج إلى تنفيذ لها تسلسل محدد جيدًا.
على سبيل المثال، تحتوي لغة هاسكل على العديد من الدوال للتعامل مع نظام الملفات الأوسع ، بما في ذلك دالة للتحقق من وجود ملف وأخرى لحذف ملف. توقيعات أنواعها هي:
doesFileExist :: FilePath -> IO Bool removeFile :: FilePath -> IO ()يهتم الأول بالتحقق من وجود ملف معين، ونتيجة لذلك، يُخرج قيمة منطقية داخل IOالموناد. أما الدالة الثانية، على النقيض، فتهتم فقط بالتعامل مع نظام الملفات بحيث IOيكون الحاوية التي تُخرجها فارغة.
IOولا يقتصر الأمر على إدخال/إخراج الملفات فقط؛ بل يسمح أيضًا بإدخال/إخراج المستخدم، وبالإضافة إلى اختصارات بناء الجملة الإجرائية، يمكنه محاكاة برنامج " مرحباً بالعالم !" النموذجي:
main :: IO () main = do putStrLn "Hello, world!" putStrLn "What is your name, user?" name <- getLine putStrLn ( "Nice to meet you, " ++ name ++ "!" )بعد إزالة السكريات، يُترجم هذا إلى خط الأنابيب الأحادي التالي ( >>في لغة هاسكل، هو مجرد شكل مختلف من bind عندما تكون التأثيرات الأحادية فقط هي المهمة ويمكن تجاهل النتيجة الأساسية):
main :: IO () main = putStrLn "Hello, world!" >> putStrLn "What is your name, user?" >> getLine >>= ( \ name -> putStrLn ( "Nice to meet you, " ++ name ++ "!" ))موناد الكاتب (جافا)
من المواقف الشائعة الأخرى الاحتفاظ بملف سجل أو تسجيل تقدم البرنامج. أحيانًا، قد يرغب المبرمج في تسجيل بيانات تقنية أكثر تحديدًا لأغراض التحليل أو تصحيح الأخطاء لاحقًا . يمكن لـ Writer monad التعامل مع هذه المهام من خلال إنشاء مخرجات إضافية تتراكم خطوة بخطوة.
لإظهار كيف أن نمط الموناد لا يقتصر على اللغات الوظيفية بشكل أساسي، يقوم هذا المثال بتنفيذ Writerموناد في جافا ، مخزنة في فئة تمثل Writerالموناد.
استيراد java.util.ArrayList ؛ استيراد java.util.List ؛ استيراد java.util.function.Function ؛كاتب السجل < T > ( T قيمة ، قائمة < سلسلة > سجل ) { // العمليات الداخلية هنا ... }تعريف الوحدة بسيط للغاية أيضاً:
كاتب السجلات < T > ( T قيمة ، قائمة < سلسلة > سجل ) { // ...public static <T> Writer <T> unit ( T value ) { return new Writer < > ( value , new ArrayList <> ( ) ) ; } }يكفي استخدام الوحدة لتعريف وظائف بسيطة تُخرج Writerكائنات مع ملاحظات تصحيح الأخطاء:
استيراد java.util.List ;class Ops { private Ops () {}public static Writer <Integer> squared ( int x ) { return new Writer < > ( x * x , List.of ( String.format ( " %d was squared. " , x ) ) ) ; }public static Writer <Integer> halved ( int x ) { return new Writer < > ( x / 2 , List.of ( String.format ( " %d was halved. ” , x ) ) ) ; } }لا يزال الموناد الحقيقي يتطلب الربط ، ولكن بالنسبة لـ Writer، تجمع هذه العملية السجل الحالي مع السجل الناتج عن تطبيق تحويل:
كاتب السجلات < T > ( T قيمة ، قائمة < سلسلة > سجل ) { // ...public <U> Writer <U> bind ( Function < T , Writer <U> > transform ) { Writer <U> result = transform.apply ( this.value ) ; List <String> newLog = new ArrayList < > ( this.log ) ; newLog.addAll ( result.log ( ) ) ; return new Writer < > ( result.value ( ) , newLog ) ; } }يمكن الآن ربط الدوال النموذجية معًا باستخدام bind ، والتي يمكن تمثيلها باستخدام ربط الأساليب :
Writer <Integer> result = Writer.unit ( 4 ) .bind ( Ops :: squared ) .bind ( Ops :: halved ) ;والنتيجة النهائية هي فصل واضح بين الاهتمامات المتعلقة بإجراء العمليات الحسابية وتجميع مخرجات السجل لفحصها لاحقًا:
System.out.println ( result.value ( ) ); // 8 System.out.println ( result.log ( ) ) ; // [ تم تربيع 4 ، وتم تنصيف 16. ]موناد البيئة
تسمح موناد البيئة (وتُسمى أيضًا موناد القارئ وموناد الدالة ) بأن تعتمد عملية حسابية على قيم من بيئة مشتركة. يقوم مُنشئ نوع الموناد بربط النوع T بدوال من النوع E → T ، حيث E هو نوع البيئة المشتركة. دوال الموناد هي:
العمليات الأحادية التالية مفيدة:
تُستخدم عملية "ask" لاسترجاع السياق الحالي، بينما تُنفّذ عملية "local" عملية حسابية في سياق فرعي مُعدّل. وكما هو الحال في موناد الحالة، يمكن استدعاء العمليات الحسابية في موناد البيئة ببساطة عن طريق توفير قيمة بيئية وتطبيقها على نسخة من الموناد.
بشكل رسمي، القيمة في موناد البيئة تعادل دالة مع وسيط إضافي مجهول؛ الإرجاع والربط يعادلان المجمعات K و S ، على التوالي، في حساب التفاضل والتكامل SKI .
مونادات الدولة
تُمكّن موناد الحالة المبرمج من إرفاق معلومات الحالة من أي نوع بعملية حسابية. وبأي نوع قيمة، يكون النوع المقابل في موناد الحالة دالة تقبل حالة، ثم تُخرج حالة جديدة (من النوع s) مع قيمة مُعادة (من النوع t). يشبه هذا موناد البيئة، إلا أنه يُعيد حالة جديدة أيضًا، وبالتالي يسمح بنمذجة بيئة قابلة للتغيير .
نوع الحالة s t = s -> ( t , s )لاحظ أن هذه الوحدة تأخذ مُعامل نوع، وهو نوع معلومات الحالة. تُعرَّف عمليات الوحدة كما يلي:
-- تُعيد الدالة "return" القيمة المُعطاة دون تغيير الحالة. return x = s - > ( x , s ) -- تُعدّل الدالة "bind" المتغير m بحيث تُطبّق الدالة f على نتيجته. m >>= f = r -> let ( x , s ) = m r in ( f x ) sتشمل عمليات الحالة المفيدة ما يلي:
get = s - > ( s , s ) -- فحص الحالة عند هذه النقطة في الحساب. put s = _ - > ( () , s ) -- استبدال الحالة. modify f = s - > ( () , f s ) -- تحديث الحالةعملية أخرى تُطبّق موناد الحالة على حالة أولية معينة:
runState :: State s a -> s -> ( a , s ) runState t s = t sتُعدّ كتل do في موناد الحالة عبارة عن تسلسلات من العمليات التي يمكنها فحص وتحديث بيانات الحالة.
بصورة غير رسمية، تقوم موناد الحالة من نوع الحالة S بربط نوع القيم المرجعة T بالدوال من النوعحيث S هي الحالة الأساسية. دالة الإرجاع ودالة الربط هما:
- .
من وجهة نظر نظرية الفئات، يتم اشتقاق موناد الحالة من الاقتران بين دالة الضرب والدالة الأسية، والتي توجد في أي فئة مغلقة ديكارتية بحكم التعريف.
موناد الاستمرار
موناد الاستمرار [ p ] ذو نوع الإرجاع R يحوّل النوع T إلى دوال من النوعيُستخدم هذا الأسلوب لنمذجة نمط تمرير الاستمرارية . وتكون دوال الإرجاع والربط كما يلي:
يتم تعريف دالة الاستدعاء مع الاستمرار الحالي على النحو التالي :
تسجيل البرنامج
الكود التالي هو كود زائف.لنفترض أن لدينا دالتين fooو bar، من النوعين
foo : int -> int bar : int -> intأي أن كلتا الدالتين تأخذان عددًا صحيحًا كمدخل وتعيدان عددًا صحيحًا آخر. بعد ذلك، يمكننا تطبيق الدالتين بالتتابع كما يلي:
foo ( bar x )حيث تكون النتيجة هي نتيجة fooتطبيق على نتيجة barتطبيق على x.
لكن لنفترض أننا نقوم بتصحيح أخطاء برنامجنا، ونرغب في إضافة رسائل تسجيل إلى fooو bar. لذلك نغير الأنواع على النحو التالي:
foo : int -> int * string bar : int -> int * stringبحيث تُرجع كلتا الدالتين مجموعة من العناصر، مع نتيجة التطبيق كعدد صحيح، ورسالة تسجيل تحتوي على معلومات حول الدالة المطبقة وجميع الدوال المطبقة سابقًا كسلسلة نصية.
لسوء الحظ، هذا يعني أنه لم يعد بإمكاننا دمجfoo الدالتين bar، لأن نوع مدخلاتهما intغير متوافق مع نوع مخرجاتهما int * string. ورغم أنه يمكننا استعادة إمكانية الدمج بتعديل أنواع كل دالة لتكون int * string -> int * string، إلا أن هذا سيتطلب إضافة شيفرة نمطية لكل دالة لاستخراج العدد الصحيح من المجموعة، وهو أمر سيصبح شاقًا مع ازدياد عدد هذه الدوال.
بدلاً من ذلك، دعونا نحدد دالة مساعدة لتجريد هذا الكود النمطي نيابةً عنا:
ربط : int * string -> ( int -> int * string ) -> int * stringbindتستقبل الدالة المدخلات، وهي عبارة عن زوج من عدد صحيح وسلسلة نصية، ثم تستقبل دالة (مثل الدالة `input` foo) تُحوّل العدد الصحيح إلى زوج من عدد صحيح وسلسلة نصية. يكون الناتج زوجًا من عدد صحيح وسلسلة نصية، وهو نتيجة تطبيق الدالة `input` على العدد الصحيح الموجود داخل زوج الإدخال. بهذه الطريقة، نحتاج فقط إلى كتابة شيفرة أساسية لاستخراج العدد الصحيح من الزوج مرة واحدة bind.
لقد استعدنا الآن بعضاً من إمكانية التركيب. على سبيل المثال:
ربط ( ربط ( س ، ص ) شريط ) fooحيث يمثل q(x,s) زوجًا من الأعداد الصحيحة والسلاسل النصية .
ولتوضيح الفوائد بشكل أكبر، دعونا نُعرّف عامل التشغيل الوسطي كاسم بديل لـ bind:
( >>= ) : int * string -> ( int -> int * string ) -> int * stringإذن هذا t >>= fهو نفسه bind t f.
ثم يصبح المثال أعلاه كالتالي:
(( x , s ) >>= bar ) >>= fooوأخيرًا، نقوم بتعريف دالة جديدة لتجنب الكتابة (x, "")في كل مرة نرغب فيها بإنشاء رسالة تسجيل فارغة، حيث ""تكون السلسلة الفارغة.
القيمة المُعادة : عدد صحيح -> عدد صحيح * سلسلة نصيةوالذي يلتف xحول المجموعة الموصوفة أعلاه.
والنتيجة هي مسار لتسجيل الرسائل:
(( إرجاع x ) >>= bar ) >>= fooوهذا يسمح لنا بتسجيل تأثيرات barو fooعلى بسهولة أكبر x.
int * stringيشير إلى قيمة أحادية مشفرة زائفًا . [ q ]bind و returnهما مماثلان للدوال المقابلة التي تحمل نفس الاسم. تشكل int * stringو bindو returnمونادًا.
المونادات المضافة
الموناد الجمعي هو موناد مزود بعامل ثنائي مغلق وتجميعي إضافي mplus وعنصر محايد تحت mplus يُسمى mzero . Maybeيمكن اعتبار الموناد جمعيًا، Nothingحيث mzero هو العنصر المحايد، و mplus هو أحد أشكال عامل OR . الموناد هو أيضًا موناد جمعي، حيث تعمل القائمة الفارغة كـ mzero ويعمل عامل الربط كـ mplus .List[]++
بشكل بديهي، يُمثل mzero غلافًا أحاديًا بدون قيمة من نوع أساسي، ولكنه يُعتبر أيضًا "صفرًا" (وليس "واحدًا") لأنه يعمل كممتص للدالة bind ، حيث يُعيد mzero عند ربطه بدالة أحادية. هذه الخاصية ثنائية الجانب، وستُعيد bind أيضًا mzero عند ربط أي قيمة بدالة أحادية صفرية .
من منظور نظرية الفئات، يُعتبر الموناد الجمعي مرة واحدة مونيدًا على الدوال المونادية ذات الربط (كما هو الحال مع جميع المونادات)، ومرة أخرى على القيم المونادية عبر mplus . [ 32 ] [ r ]
المونادات الحرة
أحيانًا، قد يكون المخطط العام للموناد مفيدًا، لكن لا يوجد نمط بسيط يوصي بموناد دون آخر. هنا يأتي دور الموناد الحر ؛ فباعتباره كائنًا حرًا في فئة المونادات، يمكنه تمثيل البنية المونادية دون أي قيود محددة تتجاوز قوانين الموناد نفسها. وكما أن المونيد الحر يجمع العناصر دون تقييم، فإن الموناد الحر يسمح بتسلسل العمليات الحسابية باستخدام علامات لتلبية نظام النوع، ولكنه لا يفرض أي دلالات أعمق في حد ذاته.
على سبيل المثال، من خلال العمل بالكامل عبر علامتي ` Justand` و`and` Nothing، Maybeتُصبح الموناد مونادًا حرًا. Listفي المقابل، لا تُعتبر الموناد مونادًا حرًا لأنها تُدخل حقائق إضافية ومحددة حول القوائم (مثل ` append` ) في تعريفها. مثال أخير هو موناد حر مجرد:
بيانات حرة f a = بيور a | حرة ( f ( حرة f a ))الوحدة :: أ -> وحدة حرة f أ س = س نقية سربط :: دالة f => تحرير f a -> ( a -> تحرير f b ) -> تحرير f b ربط ( نقي x ) f = f x ربط ( تحرير x ) f = تحرير ( fmap ( \ y -> ربط y f ) x )ومع ذلك، فإن المونادات الحرة لا تقتصر على قائمة مرتبطة كما هو الحال في هذا المثال، ويمكن بناؤها حول هياكل أخرى مثل الأشجار .
قد يبدو استخدام المونادات الحرة عن قصد غير عملي في البداية، لكن طبيعتها الرسمية تجعلها مناسبة تمامًا للمشاكل النحوية. يمكن استخدام الموناد الحرة لتتبع النحو والنوع مع ترك الدلالات لوقت لاحق، وقد وجدت استخدامًا في المحللات اللغوية والمفسرات نتيجة لذلك. [ 33 ] كما طبقها آخرون على مشاكل تشغيلية أكثر ديناميكية، مثل توفير عناصر قابلة للتكرار داخل اللغة. [ 34 ]
كوموناد
إلى جانب توليد المونادات بخصائص إضافية، يمكن تعريف موناد مشترك لأي موناد مُعطى . من الناحية النظرية، إذا كانت المونادات تُمثل عمليات حسابية مبنية على قيم أساسية، فيمكن اعتبار المونادات المشتركة بمثابة اختزالات تعود إلى القيم. لا يمكن، بمعنى ما، "فك" شفرة الموناد بالكامل؛ فبمجرد تغليف قيمة داخل موناد، تبقى محصورة هناك مع أي آثار جانبية (وهذا أمر جيد في البرمجة الوظيفية البحتة). مع ذلك، في بعض الأحيان، تكمن المشكلة في استهلاك البيانات السياقية، والتي يمكن للمونادات المشتركة نمذجتها بشكل صريح.
من الناحية التقنية، يُعدّ الكوموناد الثنائي الفئوي للموناد، ما يعني بشكل عام أنه سيحتوي على نفس المكونات المطلوبة، ولكن مع عكس اتجاه توقيعات الأنواع . انطلاقًا من تعريف الموناد المتمحور حول الربط ، يتكون الكوموناد مما يلي:
- مُنشئ نوع W الذي يُشير إلى النوع ذي الرتبة الأعلى WT
- يستخرج ثنائي الوحدة ، والذي يُسمى هنا counit ، القيمة الأساسية من الموناد المشترك:
counit(wa) : WT → T
- انعكاس الربط (المُمثَّل أيضًا بـ
=>>) الذي يمتد على شكل سلسلة من الدوال المختزلة:
(wa =>> f) : (WU, WU → T) → WT [ s ]
يجب أن يفي كل من extend و counit أيضاً بقوانين الموناد الثنائية:
وحدة ∘ ( (wa =>> f) → wb ) ↔ f(wa) → b wa =>> counit ↔ wa wa ( (=>> f(wx = wa)) → wb (=>> g(wy = wb)) → wc ) ↔ ( wa (=>> f(wx = wa)) → wb ) (=>> g(wy = wb)) → wc
على غرار المونادات، يمكن أيضًا اشتقاق المونادات المشتركة من الدوال باستخدام ثنائي الربط :
- تأخذ الدالة duplicate قيمةً كوموناديةً بالفعل وتغلفها في طبقة أخرى من البنية الكومونادية:
duplicate(wa) : WT → W (WT)
مع أن عمليات مثل التمديد تُعكس، إلا أن الكوموناد لا يعكس الدوال التي يعمل عليها، وبالتالي، تظل الكومونادات دوالًا مع دالة map ، وليست دوالًا مشتركة . ويجب أن يلتزم التعريف البديل الذي يتضمن دوال duplicate و counit و map بقوانين الكوموناد الخاصة به أيضًا.
((خريطة مكررة) ∘ مكرر) wa ↔ (مكرر ∘ مكرر) wa ↔ wwwa ((وحدة الخريطة) ∘ مكررة) وا ↔ (وحدة ∘ مكررة) وا ↔ وا ((map map φ) ∘ duplicate) wa ↔ (duplicate ∘ (map φ)) wa ↔ wwb
وكما هو الحال مع المونادات، يمكن تحويل الشكلين تلقائيًا:
(خريطة φ) wa ↔ wa =>> (φ ∘ counit) wx تكرار wa ↔ wa =>> wx
wa =>> f(wx) ↔ ((map f) ∘ duplicate) wa
من الأمثلة البسيطة على ذلك دالة المنتج المشتركة (Product comonad )، التي تُخرج قيمًا بناءً على قيمة مُدخلة وبيانات بيئية مشتركة. Productتُعدّ دالة المنتج المشتركة ثنائية دالة Writerالمنتج (monad)، وهي في الواقع مُطابقة لها Reader(سيتم شرح كليهما لاحقًا). Productويكمن Readerالاختلاف بينهما فقط في توقيعات الدوال التي تقبلها، وكيفية تكاملها مع تلك الدوال من خلال تغليف القيم أو فك تغليفها.
ومن الأمثلة الأقل وضوحًا، الموناد المتدفق ، الذي يُستخدم لتمثيل تدفقات البيانات وإضافة مرشحات للإشارات الواردة باستخدام دالة التمديد . ورغم أنه ليس شائعًا كالمونادات، فقد وجد الباحثون أن المونادات مفيدة بشكل خاص في معالجة التدفقات ونمذجة برمجة تدفق البيانات . [ 35 ] [ 36 ]
بسبب تعريفاتها الدقيقة، لا يمكن ببساطة نقل الكائنات ذهابًا وإيابًا بين المونادات والكومونادات. وباعتبارها تجريدًا أعلى، يمكن للأسهم أن تشمل كلا البنيتين، لكن إيجاد طرق أكثر دقة لدمج الشفرة المونادية والكومونادية لا يزال مجالًا بحثيًا نشطًا. [ 37 ] [ 38 ]
انظر أيضاً
بدائل لنمذجة العمليات الحسابية:
- تُعد أنظمة التأثير (وخاصة معالجات التأثير الجبرية) طريقة مختلفة لوصف الآثار الجانبية كأنواع
- تُعدّ أنواع التفرد نهجًا ثالثًا للتعامل مع الآثار الجانبية في اللغات الوظيفية
مفاهيم التصميم ذات الصلة:
- يركز البرمجة الموجهة نحو الجوانب على فصل التعليمات البرمجية المساعدة لتحسين النمطية والبساطة
- إن عكس التحكم هو المبدأ المجرد لاستدعاء وظائف محددة من إطار عمل شامل
- تُعدّ فئات الأنواع ميزة لغوية خاصة تُستخدم لتنفيذ المونادات وغيرها من الهياكل في لغة هاسكل.
- يُعد نمط المُزخرف طريقة أكثر واقعية ومخصصة لتحقيق فوائد مماثلة في البرمجة الكائنية التوجه
تعميمات المونادات:
- تُعمم الدوال التطبيقية من المونادات عن طريق الاحتفاظ فقط بالوحدة والقوانين التي تربطها بالخريطة.
- تستخدم الأسهم بنية إضافية لدمج الدوال البسيطة والمونادات ضمن واجهة واحدة.
- تعمل محولات الموناد على مونادات متميزة لدمجها بشكل معياري.
ملحوظات
- ↑ بشكل أكثر رسمية، الموناد هو أحادي في فئة الدوال الداخلية .
- ↑ نظرًا لأن الدوال التي تعمل على متغيرات حرة متعددةشائعة في البرمجة، فإن المونادات كما هو موضح في هذه المقالة هي من الناحية الفنية ما يسميه منظرو الفئات المونادات القوية . [ 3 ]
- 1 2 يمكن إيجاد الدافع المحدد لـ Maybe في (Hutton 2016). [ 7 ]
- 1 2 يُجرّد هاتون مفهومًا يُسمى a،
bindوالذي عند إعطائه نوعًا a قد يفشل، وتعيينًا a → b قد يفشل، ينتج عنه نتيجة b قد تفشل. (هاتون، 2016) [ 7 ] - يشير (هاتون 2016) إلى أن كلمة "فقط" قد تدل على النجاح، وأن كلمة "لا شيء" قد تدل على الفشل. [ 7 ]
- ↑ من الناحية الدلالية، فإن M ليس تافهاً ويمثل دالة داخلية على فئة جميع القيم المكتوبة بشكل جيد:
- ↑ في حين أن الدالة (المتعددة الأشكال بارامتريًا) في مصطلحات البرمجة، فإن الوحدة (التي تسمى غالبًا η في نظرية الفئات) هي تحويل طبيعي رياضيًا ، والذي يربط بين الدوال :
- على النقيض من ذلك، فإن الربط ليس تحولًا طبيعيًا في نظرية الفئات، بل هو بالأحرى امتدادالذي يرفع عملية الربط (من القيم إلى العمليات الحسابية) إلى عملية تحويل بين العمليات الحسابية:
- ↑ من الناحية الدقيقة، قد لا يكون الربط ترابطيًا رسميًا في جميع السياقات لأنه يتوافق مع التطبيق ضمن حساب لامدا ، وليس الرياضيات. في حساب لامدا الدقيق، قد يتطلب تقييم الربط أولًا تغليف الحد الأيمن (عند ربط قيمتين أحاديتين) أو الربط نفسه (بين دالتين أحاديتين) بدالة مجهولة حتى يظل بإمكانه قبول المدخلات من اليسار. [ 10 ]
- ↑ بدءًا من إصدار GHC 7.10.1 وما بعده، بدأت لغة هاسكل في تطبيق اقتراح هاسكل لعام 2014 بشأن الموناد التطبيقية (AMP) والذي يتطلب إدراج 7 أسطر من التعليمات البرمجية في أي وحدات موجودة تستخدم المونادات. [ 25 ]
- ↑ عادةً ما يُشار إلى هذه التحويلات الطبيعية بالتشاكلات η و μ. أي أن: η و μ تشيران إلى الوحدة والوصل على التوالي.
- ↑ حتى أن بعض اللغات مثل Haskell توفر اسمًا مستعارًا لـ map في سياقات أخرى يسمى
lift، إلى جانب إصدارات متعددة لعدد المعلمات المختلفة، وهي تفاصيل تم تجاهلها هنا. - ↑ في نظرية الفئات،
Identityيمكن أيضًا اعتبار الموناد ناتجًا عن اقتران أي دالة مع معكوسها. - ↑ تنظر نظرية الفئات إلى هذه المجموعات الأحادية على أنها اقترانات بين الدالة الحرة والدوال المختلفة من فئة المجموعات إلى فئة الأحاديات .
- ↑ هنا تتمثل مهمة المبرمج في إنشاء أحادي مناسب، أو ربما اختيار أحادي من مكتبة.
- ↑ قد يرغب القارئ في متابعة موضوع ماكان [ 6 ] ومقارنته بالأنواع أدناه.
- 1 2 في هذه الحالة،
bindقام المبرمج بلصق عنصر فيstringمكان كان موجودًا فيه سابقًا عنصر واحد فقطinteger؛ أي أن المبرمج قام بإنشاء عنصر إضافي : مجموعة(x,s)، المشار إليهاint * stringفي الشفرة الزائفة § أعلاه . - ↑ جبريًا، تشبه العلاقة بين جانبي المونويد (غير التبادليين) علاقة شبه الحلقة ، وبعض المونادات الجمعية تُصنَّف ضمنها. مع ذلك، لا تُحقق جميع المونادات الجمعية قوانين التوزيع حتى لشبه الحلقة. [ 32 ]
- ↑ في لغة Haskell، يتم تعريف extend فعليًا مع تبديل المدخلات، ولكن نظرًا لعدم استخدام currying في هذه المقالة، يتم تعريفه هنا على أنه الثنائي الدقيق لـ bind .
مراجع
- 1 2 3 4 5 6 أوسوليفان، برايان؛ غورزن، جون؛ ستيوارت، دون (2009). "المونادات" . هاسكل في العالم الحقيقي . سيباستوبول، كاليفورنيا: أورايلي ميديا. الفصل 14. ISBN 978-0596514983.
- 1 2 وادلر، فيليب (يونيو 1990). فهم المونادات . مؤتمر ACM حول لغة LISP والبرمجة الوظيفية. نيس، فرنسا. CiteSeerX 10.1.1.33.5381 .
- 1 2 3 موجي، يوجينيو (1991). "مفاهيم الحوسبة والمونادات" (ملف PDF) . المعلومات والحوسبة . 93 (1): 55-92 . CiteSeerX 10.1.1.158.5275 . doi : 10.1016/0890-5401(91)90052-4 .
- 1 2 3 4 5 وادلر، فيليب (يناير 1992). جوهر البرمجة الوظيفية . الندوة السنوية التاسعة عشرة لجمعية الحوسبة الآلية حول مبادئ لغات البرمجة. ألبوكيرك، نيو مكسيكو. CiteSeerX 10.1.1.38.9516 .
- 1 2 هوداك، بول ؛ بيترسون، جون؛ فاسيل، جوزيف (1999). "حول المونادات" . مقدمة مبسطة إلى هاسكل 98. الفصل 9.
- 1 2 إجابة سي. أ. ماكان (23 يوليو 2010 الساعة 23:39) كيف ولماذا تعمل موناد هاسكل كونت؟
- 1 2 3 غراهام هاتون (2016) البرمجة بلغة هاسكل، الطبعة الثانية
- 1 2 بيكمان، برايان (21 نوفمبر 2012). "لا تخف من الموناد" . يوتيوب .
- ↑ سبيفي، مايك (1990). "نظرية وظيفية للاستثناءات" (ملف PDF) . علم برمجة الحاسوب . 14 (1): 25-42 . doi : 10.1016/0167-6423(90)90056-J .
- ↑ "قوانين الموناد" . هاسكل ويكي . haskell.org . تم الاطلاع عليه بتاريخ 14 أكتوبر 2018 .
- ↑ "ما ليس موناد" . 7 أكتوبر 2018.
- ↑ دي موتر، وولفغانغ (1997). المونادات كأساس نظري لبرمجة الجوانب الموجهة (ملف PDF) . ورشة العمل الدولية حول برمجة الجوانب الموجهة في مؤتمر ECOOP. يوفاسكولا، فنلندا. CiteSeerX 10.1.1.25.8262 .
- ↑ "Monad (بدون استعارات)" . HaskellWiki . 1 نوفمبر 2009. تم الاطلاع عليه بتاريخ 24 أكتوبر 2018 .
- ↑ أوسوليفان، برايان؛ غورزن، جون؛ ستيوارت، دون (2009). "استخدام بارسيك" . هاسكل في العالم الحقيقي . سيباستوبول، كاليفورنيا: أورايلي ميديا. الفصل 16. ISBN 978-0596514983.
- ↑ ستيوارت، دون (17 مايو 2007). "صمم مدير النوافذ الخاص بك: تتبع التركيز باستخدام سحاب" . Control.Monad.Writer . مؤرشف من الأصل في 20 فبراير 2018. تم الاطلاع عليه في 19 نوفمبر 2018 .
- ↑ بنتون، نيك (2015). "المونادات الفئوية وبرمجة الحاسوب" (ملف PDF) . جمعية لندن الرياضية، إمباكت 150 قصة . 1. تاريخ الاسترجاع: 19 نوفمبر 2018 .
- ↑ كيسليوف، أولاغ (2007). "الاستمراريات المحددة في أنظمة التشغيل". نمذجة السياق واستخدامه . سلسلة محاضرات في علوم الحاسوب. المجلد 4635. سبرينغر برلين هايدلبرغ. الصفحات 291-302 . doi : 10.1007/978-3-540-74255-5_22 . ISBN 978-3-540-74255-5.
- ↑ ماير، إريك (27 مارس 2012). "فأرتك هي قاعدة بيانات" . مجلة ACM Queue . 10 (3): 20-33 . doi : 10.1145/2168796.2169076 .
- ↑ إيفرسون، كينيث (سبتمبر 1987). "قاموس لغة APL" . APL Quote Quad . 18 (1): 5–40 . doi : 10.1145/36983.36984 . ISSN 1088-6826 . S2CID 18301178. تاريخ الاسترجاع: 19 نوفمبر 2018 .
- ↑ كلايسلي، هاينريش (1965). "كل بناء قياسي يُستحث بواسطة زوج من الدوال المرافقة" (ملف PDF) . وقائع الجمعية الرياضية الأمريكية . 16 (3): 544-546 . doi : 10.1090/S0002-9939-1965-0177024-4 . تاريخ الاسترجاع: 19 نوفمبر 2018 .
- ^ بيبر، بيتر، أد. (نوفمبر 1997). لغة البرمجة أوبال (التقرير الفني) ( الطبعة الخامسة المصححة). Fachbereich Informatik، جامعة برلين التقنية. سيتيسيركس 10.1.1.40.2748 .
- ↑ موجي، يوجينيو (يونيو 1989). حساب لامدا الحسابي والمونادات (ملف PDF) . الندوة السنوية الرابعة حول المنطق في علوم الحاسوب. باسيفيك غروف، كاليفورنيا. CiteSeerX 10.1.1.26.2787 .
- 1 2 بيتون جونز، سيمون ل .؛ وادلر، فيليب (يناير 1993). البرمجة الوظيفية الإجرائية (ملف PDF) . الندوة السنوية العشرون لجمعية ACM حول مبادئ لغات البرمجة. تشارلستون، كارولاينا الجنوبية. CiteSeerX 10.1.1.53.2504 .
- ↑ برنت يورجي تايب كلاسوبيديا
- ↑ Stack Overflow (8 سبتمبر 2017) تعريف موناد جديد في هاسكل لا يُنشئ أي مثيل لـ Applicative
- ↑ برنت يورجي مونويدز
- ↑ "دالة تطبيقية" . ويكي هاسكل . Haskell.org. 7 مايو 2018. مؤرشف من الأصل في 30 أكتوبر 2018. تم الاطلاع عليه في 20 نوفمبر 2018 .
- 1 2 جيبارد، كالي (30 ديسمبر 2011). "المونادات كحاويات" . هاسكل ويكي . Haskell.org. مؤرشف من الأصل في 14 ديسمبر 2017. تم الاسترجاع في 20 نوفمبر 2018 .
- 1 2 بيبوني، دان (7 أغسطس 2006). "كان بإمكانك اختراع المونادات! (وربما فعلت ذلك بالفعل.)" . حي اللانهاية . مؤرشف من الأصل في 24 أكتوبر 2018. تم الاسترجاع في 16 أكتوبر 2018 .
- ↑ "بعض التفاصيل حول تعابير الحساب في لغة F#" . 21 سبتمبر 2007. تم الاطلاع عليه في 9 أكتوبر 2018 .
- ↑ جايلز، بريت (12 أغسطس 2013). "الرفع" . هاسكل ويكي . Haskell.org. مؤرشف من الأصل في 29 يناير 2018. تم الاسترجاع في 25 نوفمبر 2018 .
- 1 2 ريفاس، إكسيكيل؛ جاسكيليوف، ماورو؛ شريفرز، توم (يوليو 2015). من المونويدات إلى شبه الحلقات: جوهر MonadPlus وAlternative (ملف PDF) . المؤتمر الدولي السابع عشر لجمعية ACM حول مبادئ وممارسات البرمجة التصريحية. سيينا، إيطاليا. CiteSeerX 10.1.1.703.342 .
- ↑ سويرسترا، ووتر (2008). "أنواع البيانات حسب الطلب" (ملف PDF) . لؤلؤة وظيفية. مجلة البرمجة الوظيفية . 18 (4). مطبعة جامعة كامبريدج: 423-436 . CiteSeerX 10.1.1.101.4131 . doi : 10.1017/s0956796808006758 . ISSN 1469-7653 . S2CID 21038598 .
- ↑ كيسليوف، أوليغ (مايو 2012). شريفرز، توم؛ ثيمان، بيتر (محرران). المُكرِّرون (ملف PDF) . الندوة الدولية حول البرمجة الوظيفية والمنطقية. سلسلة محاضرات في علوم الحاسوب. المجلد 7294. كوبي، اليابان: سبرينغر-فيرلاغ. الصفحات 166-181 . doi : 10.1007/978-3-642-29822-6_15 . ISBN 978-3-642-29822-6.
- ↑ أوستالو، تارمو؛ فيني، فارمو (يوليو 2005). هورفاث، زولتان (محرر). جوهر برمجة تدفق البيانات (ملف PDF) . المدرسة الصيفية الأولى، البرمجة الوظيفية في أوروبا الوسطى. سلسلة محاضرات في علوم الحاسوب. المجلد 4164. بودابست، المجر: سبرينغر-فيرلاغ. الصفحات 135-167 . CiteSeerX 10.1.1.62.2047 . ISBN 978-3-540-46845-5.
- ↑ أوستالو، تارمو؛ فيني، فارمو (يونيو 2008). "مفاهيم الحوسبة المتجانسة" . ملاحظات إلكترونية في علوم الحاسوب النظرية . 203 (5). إلسيفير: 263-284 . doi : 10.1016/j.entcs.2008.05.029 . ISSN 1571-0661 .
- ↑ باور، جون؛ واتانابي، هيروشي (مايو 2002). "دمج الموناد والكوموناد" (ملف PDF) . علوم الحاسوب النظرية . 280 ( 1-2 ). إلسيفير: 137-162 . CiteSeerX 10.1.1.35.4130 . doi : 10.1016/s0304-3975(01)00024-x . ISSN 0304-3975 .
- ↑ غابواردي، ماركو؛ كاتسوماتا، شين-يا؛ أوركارد، دومينيك؛ بروفارت، فلافيان؛ أوستالو، تارمو (سبتمبر 2016). دمج التأثيرات والتأثيرات المشتركة عبر التقييم (ملف PDF) . المؤتمر الدولي الحادي والعشرون لجمعية ACM حول البرمجة الوظيفية. نارا، اليابان: جمعية آلات الحوسبة. الصفحات 476-489 . doi : 10.1145/2951913.2951939 . ISBN 978-1-4503-4219-3.
روابط خارجية
مراجع هاسكل ويكي:
- " كل شيء عن المونادات " (أصلاً بقلم جيف نيوبيرن) - مناقشة شاملة لجميع المونادات الشائعة وكيفية عملها في لغة هاسكل؛ تتضمن تشبيه "خط التجميع الآلي".
- " Typeclassopedia " (أصلها من تأليف برنت يورجي) - شرح مفصل لكيفية ترابط فئات الأنواع الرائدة في لغة هاسكل، بما في ذلك المونادات.
دروس تعليمية:
- " قبضة من المونادات " (من كتاب Haskell التعليمي على الإنترنت Learn You a Haskell for Great Good! - فصل يقدم المونادات من نقطة البداية لفئات أنواع الدوال والدوال التطبيقية، بما في ذلك الأمثلة).
- " لبعض المونادات الإضافية " - فصل ثان يشرح المزيد من التفاصيل والأمثلة، بما في ذلك
Probabilityموناد لسلاسل ماركوف . - " الوظائف، والتطبيقات، والمونادات بالصور (بقلم أديتيا بهارجافا) - درس تعليمي سريع ومضحك ومرئي عن المونادات.
حالات مثيرة للاهتمام:
- " أنابيب يونكس كوحدات إدخال/إخراج " (بقلم أوليغ كيسليوف) - مقال قصير يشرح كيف أن أنابيب يونكس هي وحدات فعالة.
- Pro Scala: Monadic Design Patterns for the Web (بقلم غريغوري ميريديث) — مخطوطة كاملة غير منشورة حول كيفية تحسين العديد من جوانب تطوير الويب في Scala باستخدام المونادات.
- 1991 في مجال الحوسبة
- البرمجة الوظيفية
- أنماط تصميم البرمجيات
- مصطلحات البرمجة
