The Documentation about the State Monad说:
put :: s -> m ()
替换monad中的状态。
我无法理解。这是否意味着函数替换内部 Monad?第二个问题:为什么返回值为m ()
而不是m s
答案 0 :(得分:6)
我认为,理解状态monad的最简单方法就是编写自己的状态并稍微使用它。研究这段代码,与其他人的例子一起玩,然后回来查看它,直到你能够从内存中写出来:
-- | 'State' is just a newtype wrapper around the type @s -> (a, s)@.
-- These are functions which are fed a state value (type @s@) as input,
-- and produce as a pair of an @a@ (the *result* of the state action)
-- and an @s@ (the *new state* after the action).
--
-- The 'State' type is fundamentally a shortcut for chaining functions
-- of types like that.
newtype State s a = State { runState :: s -> (a, s) }
instance Functor (State s) where
fmap f (State g) = State $ \s0 ->
let (a, s1) = g s
in (f a, s1)
instance Applicative (State s) where
pure a = State $ \s -> (a, s)
State ff <*> State fa = State $ \s0 ->
let (s1, f) = ff s0
(s2, a) = fa s1
in (s2, f a)
instance Monad (State s) where
return = pure
State fa >>= f = State $ \s0 ->
let (s1, a) = fa s0
(s2, b) = runState (f a) s1
in (s2, b)
-- | 'get' is just a wrapper around a function that takes the
-- incoming @s@ value and exposes it in the position where @a@
-- normally goes.
get :: State s s
get = State $ \s -> (s, s)
-- | 'put' is a wrapper around a function that discards the
-- the incoming @s@ value and replaces it with another.
put :: s -> State s ()
put s = State $ \_ -> ((), s)
这是直接用State
类型编写而不使用MonadState
类,这一点起初要简单一些。作为练习,一旦您对此感到满意,您可以尝试使用MonadState
课程进行编写。
第二个问题:为什么返回值为
m ()
而不是m s
?
据我所知,这主要是一种随意的设计选择。如果我正在设计State
类型,我可能会像这样写get
和put
,这与您的期望更相似:
-- | Modify the incoming state by applying the given function to it.
-- Produces the previous, now discarded state as a result, which is
-- often useful.
modify :: (s -> s) -> State s s
modify f = State $ \s0 -> (s, f s)
-- Now 'get' and 'put' can be written in terms of 'modify':
get :: State s s
get = modify (\s -> s)
-- | This version of 'put' returns the original, discarded state,
-- which again is often useful.
put :: s -> State s s
put s = modify (\_ -> s)
如果你有标准的'get'和'put',你可以用它来编写我修改过的'put':
-- | 'get' the incoming state, 'put' a new one in, and 'return' the old one.
replace :: s -> State s s
replace s1 = do
s0 <- get
put s1
return s0
无论如何,put
产生()
或s
是否会产生重大影响。