[英]State Monad and 'put' function in Haskell
The Documentation about the State Monad says: 有关国家Monad的文档说:
put :: s -> m ()
Replace the state inside the monad. 替换单子内部的状态。
I cannot understand that. 我不明白 Does it mean that function replace state inside Monad? 这是否意味着该函数替换Monad 内部的状态? And The second issue: Why returned value is m ()
and not ms
第二个问题:为什么返回的值是m ()
而不是ms
The easiest way to understand the state monad, I think, is just to write your own and play around with it a bit. 我认为,了解状态monad的最简单方法就是编写自己的monad并稍作练习。 Study this code, play with other people's examples, and come back and review it from time to time until you're able to write it from memory: 学习下面的代码,使用其他人的示例,然后不时回来回顾它,直到您可以从内存中编写它:
-- | '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)
This is written directly in terms of a State
type without using the MonadState
class, which is a bit simpler to understand at first. 这是直接根据State
类型编写的,而无需使用MonadState
类,这在开始时比较容易理解。 As an exercise, once you feel comfortable with this, you can try writing it with the MonadState
class. 作为练习,一旦您对此感到满意,就可以尝试使用MonadState
类编写它。
And the second issue: Why returned value is
m ()
and notms
? 第二个问题:为什么返回的值是m ()
而不是ms
?
It's mostly an arbitrary design choice, as far as I can tell. 据我所知,这基本上是一个任意的设计选择。 If I were designing the State
type I might have written get
and put
like this, which is more similar to your expectation: 如果我正在设计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)
If you have the standard 'get' and 'put' you can use that to write my modified 'put' as well: 如果您具有标准的“获取”和“放置”,则也可以使用它来编写修改后的“放置”:
-- | '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
So it doesn't make a big difference whether put
produces ()
or s
, anyway. 因此无论如何put
产生()
或s
都没有太大的区别。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.