هل يمكن لأي شخص أن يمشي لي من خلال وظيفة هاسكل هذه (المرتبطة بالدولة)؟
سؤال
tick :: State Int Int
tick = get >>= \n ->
put (n+1) >>= \y ->
return n
أنا في حيرة من أمرك كيف put (n+1)
له أي تأثير على النتيجة النهائية لهذه الوظيفة على الإطلاق. يبدو أن هذه الوظيفة يجب أن تعيد الحالة الأولية دون تغيير. أحاول أن أركض هذا في ذهني ، لكنني أظل نفاد الغرفة لأمسك الأشياء في مكانها. :
إذا تمكن شخص ما من المشي لي خلال تقييم هذه الوظيفة ، فسيكون ذلك مفيدًا حقًا.
المحلول
... كيف يضع تحديث الدولة في المقام الأول؟ يبدو أنه يجلس هناك لا يفعل شيئًا ...
آه ، الآن أفهم سؤالك. أنت تتساءل كيف put
(و get
) العمل ، أليس كذلك؟
ربما يساعد مثال في JavaScript (لغة ذات حالة قابلة للتغيير الفعلية):
var s; // mutable state
function get() { return s; }
function put(x) { s = x; }
function tick() {
var n = get();
put(n + 1);
return n;
}
آمل أن يوضح هذا ذلك ، بينما n
لا تتغير ، لا تزال الحالة الداخلية يتم تحديثها. إذا قمت بتنفيذ tick()
مرتين ، سيتم زيادة الدولة مرتين.
للعودة إلى Haskell ، إليك التعريف الكامل لـ (الأجزاء ذات الصلة) State
موناد:
newtype State s a = State { runState :: s -> (a, s) }
instance Monad (State s) where
return a = State $ \s -> (a, s)
m >>= k = State $ \s -> let
(a, r) = runState m s
in runState (k a) r
get = State $ \s -> (s, s)
put s = State $ \_ -> ((), s)
حاول الآن توسيعك tick
مثال أكثر من ذلك عن طريق الإضفاء >>=
, return
, get
و put
. نأمل أن يصبح أكثر وضوحا كيف تعمل الدولة.
نصائح أخرى
أنت على حق تمامًا. نتائج tick
"الوظيفة" هي القيمة الأولية للدولة.
الآن بالطبع ، tick
ليست "الوظيفة" الحقيقية ، ولكن حساب يمكنه القراءة والكتابة دولة قبل إنتاج نتيجة.
في هذه الحالة ، دولة تم تحديثه ، لكنك لا تزال تعيد القيمة الأصلية للحالة:
-- 4 is the inital state
ghci> runState tick 4
(4, 5)
-- 4 is the result of the tick computation, 5 is the updated state
في هذه الحالة ، نظرًا لأنك لا تفحص الدولة مرة أخرى في الداخل tick
, ، أنت لا ترى الحالة المتغيرة. ومع ذلك ، إذا حدث بعض الحساب الآخر بعد tick
, ، يمكن أن ترى الحالة المحدثة.
على سبيل المثال ، القيام به tick
مرتين (ستقرأ الحالة الثانية الحالة المحدثة):
-- 4 is the inital state
ghci> runState (tick >> tick) 4
(5, 6)
-- 5 is the result of the tick computation executed twice,
-- 6 is the updated state
قد يساعد في كتابته باستخدام do
الرموز
tick :: State Int Int
tick = do
n <- get -- get the state
put (n+1) -- save an incremented state
return n -- return the original state
بينما ال put (n+1)
لا يؤثر على نتيجة الحساب ، فإنه يغير الحالة التي يتم عقدها داخل موناد الولاية.