简体   繁体   English

状态Monad具有`put`功能

[英]State Monad with `put` Function

Looking at the State Monad's wiki , I'm trying to understand the runState and put functions. 看看State Monad的wiki ,我正在尝试理解runStateput函数。

As I understand runState , it takes a first argument of State , which has a "universe", s , and a value, a . 据我所知, runState需要State的第一个参数,它有一个“universe”, s和一个值a It takes a second argument of a universe. 它需要宇宙的第二个参数。 Finally, it returns a (a, s) where a is the new value and s is the new universe? 最后,它返回一个(a, s) ,其中a是新值, s是新宇宙?

ghci> :t runState
runState :: State s a -> s -> (a, s)

Example: 例:

ghci> let s = return "X" :: State Int String
ghci> runState s 100
("X",100)

However, I'm don't understand the put result: 但是,我不理解put结果:

ghci> runState (put 5) 1
((),5)

Since runState returns an (a, s) , why is the a of type () ? 由于runState返回(a, s)为什么是a类型的()

I'm not confident on my above attempted explanations. 我对上面的尝试解释没有信心。 Please correct me, and answer my question on put . 请纠正我,回答我的问题put

When using put with the State monad, it has the type s -> State s () . 当使用带State monad的put时,它的类型为 s -> State s ()

put sets the state to its argument, and that's all it does. put将状态设置为其参数,这就是它的全部功能。 As for its return value: it's essentially a dummy value, because there's nothing useful to return. 至于它的返回值:它本质上是一个虚拟值,因为返回没有什么用处。

This is also evident in its definition put s = state $ \\ _ -> ((), s) . 这在其定义中也很明显,即put s = state $ \\ _ -> ((), s)

The easiest way to really understand State , IMHO, is just to study the code and understand it well enough that you can implement it from memory, like I'm about to do: 真正理解State ,IMHO的最简单方法就是研究代码并充分理解它,你可以从内存中实现它,就像我要做的那样:

import Control.Applicative

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

instance Functor (State s) where
    fmap f fa = State $ \s -> f (runState fa s)

instance Applicative (State s) where
    pure a = State $ \s -> (a, s)
    ff <*> fa = State $ \ s -> 
        let (f, s') = runState ff s
            (a, s'') = runState fa s'
        in (f a, s'')

instance Monad (State s) where
    return = pure
    ma >>= f = State $ \s -> 
        let (a, s') = runState ma s
            (b, s'') = runState (f a) s'
        in (b, s'')

get :: State s s
get = State $ \s -> (s, s)

put :: s -> State s ()
put s = State $ \_ -> ((), s)

modify :: (s -> s) -> State s ()
modify f = State $ \s -> ((), f s)

Since runState returns an (a, s) , why is the a of type () ? 由于runState返回一个(a, s) ,为什么是type ()

That really is just arbitrary/conventional. 这真的只是武断的/传统的。 Taking the above as a baseline, we could just as well write modify , get and put like this: 以上述为基准,我们也可以像这样编写modifygetput

-- | Replaces the state with the result of applying it to the supplied
-- function.  The result of the action is the original state.
modify :: (s -> s) -> State s s
modify f = State $ \s -> (s, f s)

-- `get` is just what you get when you `modify` with an identity function.
get :: State s s
get = modify (\s -> s)

-- This version of `put` differs from the canonical one because it returns 
-- the old value.
put :: s -> State s s
put s = modify (\_ -> s) 

In this version modify and put have the same effects as the original, but additional produce the old state as their result. 在这个版本中, modifyput具有与原始相同的效果,但是附加产生旧状态作为结果。 Clients that use modify and put only for the effect would not generally notice the difference. 那些使用客户端modify ,并put只为效果一般不会注意到其中的差别。

Alternatively, the "return old state" versions of modify and put can be written in terms of the official ones. 或者, modifyput的“返回旧状态”版本可以根据官方版本来编写。 For example: 例如:

swap :: s -> State s s
swap s = do
    orig <- get
    put s
    return orig

So most of these operations are interdefinable, it doesn't much matter which ones are "basic" and which ones not... 因此,大多数这些操作是可以相互确定的,哪些是“基本的”而哪些不是......

The runState function takes an action in the State monad and an initial state and gives you back both the result of the calculation and the final state. runState功能需要在国家和单子初始状态的动作,给你回的计算和最终状态的两种结果。

A typical use case for runState is to hand it a complex action with an intial and to then get the final result and the state back. runState一个典型用例是将一个带有runState的复杂动作交给它,然后返回最终结果和状态。 In your example, the action is a simple primitive, put . 在您的示例中,操作是一个简单的原语, put

The put action takes a new state and produces () (pronounced unit) for a value. put动作采用新状态并为值生成() (发音为unit)。 It is very similar to how putStrLn has the type IO () It performs an action in the monad, but does not produce a useful value. 它与putStrLn具有类型IO ()方式非常类似。它在monad中执行操作,但不会产生有用的值。

So, with runState (put 5) 1 the initial state, 1 gets blown away by the new state 5 . 因此,使用runState (put 5) 1初始状态, 1被新状态5吹走。 The result the state calculation is the result of put that is () . 结果状态计算是put的结果是()

Just for kicks, lets look at something just a little more interesting: 只是为了踢,让我们看一些更有趣的东西:

runState (puts 5 >> return "hello world!") undefined
  --> ("hello world!", 5)

Here we have two actions glued together with >> (I read this as "then", it is a limited form of bind >>= where we just drop the result from the left hand side). 在这里,我们将两个动作粘在一起>> (我将其视为“然后”,它是一种有限形式的绑定>>=我们只是从左侧放下结果)。 The first action changes the state to 5 the second doesn't touch the state, but results in the string "hello world!" 第一个操作将状态更改为5 ,第二个操作将不会触及状态,但会导致字符串“hello world!” which then becomes the value of the entire calculation. 然后它成为整个计算的价值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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