简体   繁体   English

在Haskell中使用状态Monad和'put'功能

[英]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 not ms ? 第二个问题:为什么返回的值是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类型,那么我可能会这样写getput ,这与您的期望更加相似:

-- | 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM