سؤال

بعد قراءة (وقشط بعض الأقسام من) ورقة وادلر حول الموناد ، قررت العمل من خلال الورقة عن كثب ، وتحديد الحالات التطبيقية لكل من الموناد الذي يصفه. باستخدام نوع مرادف

type M a = State -> (a, State)
type State = Int

يستخدم Wadler لتحديد موناد الولاية ، لدي ما يلي (باستخدام الأسماء ذات الصلة حتى أتمكن من تعريفها بإعلان جديد في وقت لاحق).

fmap' :: (a -> b) -> M a -> M b
fmap' f m = \st -> let (a, s) = m st in (f a, s)

pure' :: a -> M a
pure' a = \st -> (a, st)

(<@>) :: M (a -> b) -> M a -> M b
sf <@> sv = \st -> let (f, st1) = sf st
                       (a, st2) = sv st1
                    in (f a, st2)

return' :: a -> M a
return' a = pure' a

bind :: M a -> (a -> M b) -> M b
m `bind` f = \st -> let (a, st1) = m st
                        (b, st2) = f a st1
                     in (b, st2)

عندما أقوم بالتبديل إلى استخدام مُنشئ النوع في إعلان جديد ، على سبيل المثال ،

newtype S a = S (State -> (a, State))

كل شيء ينهار. كل شيء مجرد تعديل بسيط ، على سبيل المثال ،

instance Functor S where
 fmap f (S m) = S (\st -> let (a, s) = m st in (f a, s)) 

instance Applicative S where
 pure a = S (\st -> (a, st))

ومع ذلك ، لا شيء يعمل في GHC بسبب حقيقة أن تعبير Lambda مخفي داخل هذا المنشئ النوع. الآن الحل الوحيد الذي أراه هو تحديد وظيفة:

isntThisAnnoying s (S m) = m s

من أجل ربط S بـ "ST" وإرجاع قيمة ، على سبيل المثال ،

fmap f m = S (\st -> let (a, s) = isntThisAnnoying st m in (f a, s))

هل هناك طريقة أخرى للقيام بذلك لا تستخدم هذه الوظائف المساعدة؟

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

المحلول

لو نظرت هنا, ، سترى أنها تحددها بهذه الطريقة:

newtype State s a = State { runState :: (s -> (a,s)) }

وذلك لإعطاء اسم Lambda الداخلي.

نصائح أخرى

الطريقة المعتادة هي تحديد newtype newtype S a = S {runState : State -> (a, State)}. ثم بدلاً من isntThisAnnoying s (S m) يمكنك كتابة runState t s أين t بالضبط مثل S m.
عليك استخدام أ newtype لأن مرادفات النوع لا يمكن أن تكون مثيلات طباعة.

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