سؤال

أنا أتعلم عن المونادات ولدي بعض الأسئلة.

هذا هو المكان الذي أنا فيه الآن.يرجى تصحيح لي حيث أخطأت.

  • ال >>= الرمز هو عامل تشغيل infix.عوامل Infix هي وظائف تأخذ وسيطتين (الجانب الأيسر والجانب الأيمن) وترجع قيمة.

  • ال >>= يسمى الرمز عامل الربط وله توقيع Monad m => m t -> (t -> m u) -> m u.ومع ذلك، يبدو أن الأنواع لا تصطف هنا.نحصل على قيمة النوع m t والوسيطة الثانية هي دالة تأخذ t.(لا أرى كيفية توصيل النقاط.)

  • يجب أن يعني هذا أن وظيفة الربط قادرة بطريقة ما على إزالة ملف m من m t من أجل الحصول على t وتمريرها إلى الوظيفة.

وهنا أسئلتي:

  • هي القدرة على إزالة m من m t شيء ممكن فقط داخل عامل الربط هذا.هل يتمتع مشغل الربط هذا ببعض الامتيازات الخاصة أو شيء من هذا القبيل؟

  • ما علاقتها بتغيرات الدولة؟أفهم (على ما أظن) أن هدف المونادات هو "تغليف" الآثار الجانبية بحيث يتم عزلها عن بقية البرنامج.ولكن ما هو دور عامل الربط في هذا؟

هل كانت مفيدة؟

المحلول

هي القدرة على إزالة "M" من "M t" وهو أمر ممكن فقط داخل عامل الربط هذا.هل يتمتع مشغل الربط هذا ببعض الامتيازات الخاصة أو شيء من هذا القبيل؟

لا يُعد Bind حالة خاصة بأي حال من الأحوال، ولكن عادةً ما يتم تعريفه في نفس الوحدة النمطية مثل نوع البيانات monads.لذلك قد يعرف (ويستخدم) التفاصيل التي لم يتم تصديرها بواسطة الوحدة.ستكون الحالة المعتادة هي أن الوحدة تقوم بتصدير نوع بيانات، ولكن ليس مُنشئاتها أو تفاصيل أخرى حول البنية الداخلية للنوع.ثم بالنسبة للكود الذي يستخدم الوحدة، تكون الأعمال الداخلية لنوع البيانات غير مرئية ولا يمكن لهذا الكود تعديل قيم هذا النوع مباشرة.

يتعارض مع تلك الوظائف المحددة داخل الوحدة، مثل بعض عوامل الربط على سبيل المثال >>=, ، يمكنهم الوصول إلى ما يريدون من الوحدة التي تم تعريفهم فيها.لذلك قد تكون مثل هذه الوظائف قادرة على القيام بأشياء لا تستطيع الوظائف "الخارجية" القيام بها.

حالة خاصة هي IO monad، نظرًا لأنه لم يتم تعريفه بواسطة وحدة نمطية، ولكنه مدمج في نظام/مترجم وقت التشغيل.هنا يعرف المترجم التفاصيل الداخلية لتطبيقه ويكشف عن وظائف مثل IO>>=.إن تطبيقات هذه الوظائف تتمتع بالفعل بامتياز خاص لأنها تعيش "خارج البرنامج"، ولكن هذه حالة خاصة ولا ينبغي ملاحظة هذه الحقيقة من داخل هاسكل.

ما علاقتها بتغيرات الدولة؟أفهم (على ما أظن) أن هدف المونادات هو "تغليف" الآثار الجانبية بحيث يتم عزلها عن بقية البرنامج.ولكن ما هو دور عامل الربط في هذا؟

ليس من الضروري حقًا أن يتعلق الأمر بتغييرات الحالة، فهذه مجرد مشكلة واحدة يمكن التعامل معها باستخدام الأنين.ال IO يتم استخدام الموناد لتنفيذ عمليات الإدخال والإخراج بترتيب معين، ولكن بشكل عام تكون المونادات مجرد طرق للجمع بين الوظائف معًا.

بشكل عام، تحدد الموناد (خاصة وظيفة الربط) الطريقة التي يجب أن تتكون بها وظائف معينة معًا لوظائف أكبر.تم تلخيص هذه الطريقة للجمع بين الوظائف في الموناد.كيف يعمل هذا الجمع بالضبط أو لماذا تريد الجمع بين الوظائف بهذه الطريقة ليس مهمًا، فالموناد يحدد فقط طريقة الجمع بين وظائف معينة بطريقة معينة.(أنظر أيضا هذه الإجابة "Monads لمبرمجي C #". حيث أكرر ذلك عدة مرات مع الأمثلة.)

نصائح أخرى

هي القدرة على إزالة "M" من "M t" وهو شيء ممكن فقط داخل عامل الربط هذا.

حسنًا، من الممكن بالتأكيد داخل عامل الربط، كما يحدد نوعه:

(>>=) :: m a -> (a -> m b) -> m b

عادةً ما يمكن لوظيفة "التشغيل" الخاصة بموناد الخاص بك القيام بذلك أيضًا (لإرجاع قيمة خالصة من حسابك).

الهدف من المونادات هو "تغليف" الآثار الجانبية بحيث يتم عزلها عن بقية البرنامج

همم.لا، المونادات تتيح لنا وضع نماذج لمفاهيم الحساب.الحسابات ذات التأثير الجانبي هي مجرد واحدة من هذه المفاهيم، كما هو الحال في الحالة، والتراجع، والاستمرارية، والتزامن، والمعاملات، والنتائج الاختيارية، والنتائج العشوائية، والحالة القابلة للإرجاع، وعدم الحتمية ...كلها يمكن وصفها بأنها موناد

أفترض أن IO monad هو ما تشير إليه.إنها أحادية غريبة بعض الشيء - فهي تولد تسلسلات من التغييرات المجردة لحالة العالم، والتي يتم تقييمها بعد ذلك من خلال وقت التشغيل.يتيح لنا Bind فقط تسلسل الأشياء بالترتيب الصحيح في IO monad - وسيقوم المترجم بعد ذلك بترجمة كل هذه الإجراءات المتسلسلة لتعديل العالم إلى تعليمات برمجية حتمية تغير حالة الجهاز.

هذا خاص جدًا بـ IO monad، وليس monads بشكل عام.

وفيما يلي تعريف فئة النوع Monad.

class  Monad m  where

    (>>=)       :: forall a b. m a -> (a -> m b) -> m b
    (>>)        :: forall a b. m a -> m b -> m b
    return      :: a -> m a
    fail        :: String -> m a

    m >> k      = m >>= \_ -> k
    fail s      = error s

كل نوع مثيل من نوع الفئة Monad يحدد الخاصة بها >>= وظيفة.هنا مثال من نوع المثيل Maybe:

instance  Monad Maybe  where

    (Just x) >>= k      = k x
    Nothing  >>= _      = Nothing

    (Just _) >>  k      = k
    Nothing  >>  _      = Nothing

    return              = Just
    fail _              = Nothing

كما نرى، لأن Maybe نسخة من >>= تم تعريفه خصيصًا لفهم Maybe مثيل النوع، ولأنه تم تعريفه في مكان لديه حق الوصول القانوني إلى data Maybe a منشئو البيانات Nothing و Just a, ، ال Maybe نسخة من >>= قادر على فك aفي Maybe a وتمريرهم من خلال.

للعمل من خلال مثال، يمكننا أن نأخذ:

x :: Maybe Integer
x = do a <- Just 5
       b <- Just (a + 1)
       return b

بعد إزالة السكر، يصبح تدوين الفعل:

x :: Maybe Integer
x = Just 5        >>= \a ->
    Just (a + 1)  >>= \b ->
    Just b

والتي تقيم على النحو التالي:

  =                  (\a ->
    Just (a + 1)  >>= \b ->
    Just b) 5

  = Just (5 + 1)  >>= \b ->
    Just b

  =                  (\b ->
    Just b) (5 + 1)

  = Just (5 + 1)

  = Just 6

الأنواع تصطف بشكل مضحك بما فيه الكفاية.إليك الطريقة.

تذكر أن الموناد هو أيضًا عامل.يتم تعريف الوظيفة التالية لجميع الوظائف:

fmap :: (Functor f) => (a -> b) -> f a -> f b

والآن السؤال:هل هذه الأنواع تصطف حقا؟نعم.نظرا لوظيفة من a ل b, ، ثم إذا كان لدينا بيئة f بحيث a متاح، لدينا بيئة f بحيث b متاح.

قياسا على القياس المنطقي:

(Functor Socrates) => (Man -> Mortal) -> Socrates Man -> Socrates Mortal

الآن، كما تعلم، الموناد هو عامل مُجهز بالربط والعودة:

return :: (Monad m) => a -> m a
(=<<) :: (Monad m) => (a -> m b) -> m a -> m b

قد لا تعرف ذلك بنفس القدر، فهو عامل مجهز بالعودة والانضمام:

join :: (Monad m) => m (m a) -> m a

انظر كيف نقوم بتقشير m.مع موناد m, ، لا يمكنك دائمًا الحصول عليه m a ل a, ، ولكن يمكنك دائمًا الحصول عليه m (m a) ل m a.

انظر الآن إلى الحجة الأولى لـ (=<<).إنها وظيفة من النوع (a -> m b).ماذا يحدث عند تمرير هذه الوظيفة إلى fmap؟لقد حصلت m a -> m (m b).لذلك، "رسم الخرائط" على m a مع وظيفة a -> m b يعطيك m (m b).لاحظ أن هذا يشبه تمامًا نوع الوسيطة join.هذا ليس مصادفة.يبدو التنفيذ المعقول لـ "bind" كما يلي:

(>>=) :: m a -> (a -> m b) -> m b
x >>= f = join (fmap f x)

في الواقع، يمكن تعريف الربط والانضمام من حيث بعضهما البعض:

join = (>>= id)

أنصحك بشدة بقراءة (http://blog.sigfpe.com/2006/08/you-could-have-invented-monads-and.html).إنه يعطي سببًا منطقيًا مثاليًا لوجود المونادات.

أفهم (على ما أظن) أن هدف المونادات هو "تغليف" الآثار الجانبية بحيث يتم عزلها عن بقية البرنامج.

انها في الواقع أكثر دقة قليلا من ذلك.تسمح لنا المونادات بنمذجة التسلسل بطريقة عامة جدًا.في كثير من الأحيان عندما تتحدث إلى أحد خبراء المجال تجدهم يقولون شيئًا مثل "أولاً، نحاول تجربة X.ثم نحاول Y، وإذا لم ينجح ذلك، فإننا نجرب Z".عندما تقوم بتنفيذ شيء كهذا في لغة تقليدية، تجد أنه غير مناسب، لذلك يتعين عليك كتابة الكثير من التعليمات البرمجية الإضافية لتغطية ما يعنيه خبير المجال بكلمة "ثم".

في Haskell، يمكنك تنفيذ ذلك كوحدة أحادية مع ترجمة "then" إلى عامل الربط.على سبيل المثال، كتبت ذات مرة برنامجًا حيث يجب تعيين عنصر من المجمعات وفقًا لقواعد معينة.بالنسبة للحالة 1، فقد أخذتها من المجموعة X.إذا كان ذلك فارغًا، فستنتقل إلى المجموعة Y.بالنسبة للحالة 2، كان عليك أن تأخذها مباشرة من المجموعة Y.وهكذا في عشرات الحالات أو نحو ذلك، بما في ذلك بعض الحالات التي حصلت فيها على أقل استخدام مؤخرًا من المجموعة X أو Y.لقد كتبت مونادًا مخصصًا خصيصًا لهذه الوظيفة حتى أتمكن من الكتابة:

case c of
   1: do {try poolX; try poolY}
   2: try poolY
   3: try $ lru [poolX, poolY]

عملت بشكل جيد للغاية.

بالطبع هذا يشمل النماذج التقليدية للتسلسل.إن IO monad هو النموذج الذي تمتلكه جميع لغات البرمجة الأخرى؛إنه مجرد خيار واضح في هاسكل وليس جزءًا من البيئة.يمنحك ST monad طفرة في ذاكرة IO، ولكن بدون الإدخال والإخراج الفعلي.من ناحية أخرى، يتيح لك State monad تقييد حالتك على قيمة واحدة من نوع مسمى.

لشيء حقا الانحناء الدماغ، انظر هذا بلوق وظيفة حول دولة متخلفة.وتنتشر الدولة في الاتجاه المعاكس لـ"الإعدام".إذا كنت تعتقد أن هذا يشبه حالة أحادية تنفذ تعليمة واحدة متبوعة بالتالية، فإن "put" سوف يرسل قيمة الحالة إلى الوراء في الوقت المناسب إلى أي "get" سابقة.ماذا في الحقيقة ما يحدث هو أنه يتم إعداد دالة متكررة بشكل متبادل ولا تنتهي إلا في حالة عدم وجود مفارقات.لست متأكدًا تمامًا من مكان استخدام مثل هذا الموناد، لكنه يوضح النقطة المتعلقة بكون المونادات نماذج للحساب.

إذا لم تكن مستعدًا لذلك، فكر فقط في bind كفاصلة منقوطة قابلة للتحميل بشكل زائد.هذا يوصلك إلى مسافة طويلة جدًا.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top