在Haskell中如何"获得"实际/获得/初始状态?

Ray*_*yne 12 monads haskell state-monad

我有一个功能:

test :: String -> State String String
test x = 
    get >>= \test ->
    let test' = x ++ test in
    put test' >>
    get >>= \test2 -> put (test2 ++ x) >>
    return "test"
Run Code Online (Sandbox Code Playgroud)

我几乎可以理解整个函数中发生了什么,并且我开始得到monad的支持.我不明白的是,当我这样做时:

runState (test "testy") "testtest"
Run Code Online (Sandbox Code Playgroud)

'test'中的'get'函数以某种方式获得初始状态"testtest".有人可以打破这个并向我解释一下吗?

我感谢任何回应!

J C*_*per 18

我原本打算将此作为评论发布,但决定进一步阐述.

严格地说,get不要"接受"一个论点.我认为很多正在发生的事情被你没有看到的东西所掩盖 - State monad的实例定义.

get实际上是MonadState类的一种方法.State monad是MonadState的一个实例,提供以下定义get:

get = State $ \s -> (s,s)
Run Code Online (Sandbox Code Playgroud)

换句话说,get只返回一个非常基本的状态monad(记住monad可以被认为是计算的"包装器"),其中计算中的任何输入s都将返回一对s作为结果.

接下来我们需要关注的是>>=,State定义的是:

m >>= k  = State $ \s -> let
    (a, s') = runState m s
    in runState (k a) s'
Run Code Online (Sandbox Code Playgroud)

因此,>>=将产生一个新的计算,在它获得初始状态之前不会计算(当它们处于"包装"形式时,所有状态计算都是如此).这个新计算的结果是通过将右侧的任何内容应用于>>=运行左侧计算的结果来实现的.(这是一个相当混乱的句子,可能需要额外的阅读或两个.)

我发现"desugar"一切正在发生的事情非常有用.这样做需要更多的打字,但应该get清楚地回答你的问题(从哪里来).请注意,以下内容应视为伪代码...

test x =
    State $ \s -> let
        (a,s') = runState (State (\s -> (s,s))) s  --substituting above defn. of 'get'
        in runState (rightSide a) s'
        where 
          rightSide test = 
            let test' = x ++ test in
            State $ \s2 -> let
            (a2, s2') = runState (State $ \_ -> ((), test')) s2  -- defn. of 'put'
            in runState (rightSide2 a2) s2'
          rightSide2 _ =
            -- etc...
Run Code Online (Sandbox Code Playgroud)

这应该很明显,我们的函数的最终结果是一个新的状态计算,需要一个初始值(s)来使其余的东西发生.您随电话s一样"testtest"提供runState.如果你s在上面的伪代码中用"testtest"代替,你会发现第一件事就是我们get以"testtest"作为"初始状态"运行.产量("testtest", "testtest")等等.

这就是get让你的初始状态"测试"的地方.希望这可以帮助!

  • 当我说它"接受"一个论点时,我想不出一个更好的词.感谢您的详细解释. (2认同)

JB.*_*JB. 5

它可能有助于您深入了解State类型构造函数的真正含义以及runState如何使用它.在GHCi中:

Prelude Control.Monad.State> :i State
newtype State s a = State {runState :: s -> (a, s)}
Prelude Control.Monad.State> :t runState
runState :: State s a -> s -> (a, s)
Run Code Online (Sandbox Code Playgroud)

State有两个参数:状态的类型和返回的类型.它被实现为一个获取初始状态并产生返回值和新状态的函数.

runState 采用这样的函数,初始输入,并且(很可能)只将一个应用于另一个以检索(结果,状态)对.

你的test函数是一个很大的State-type函数组合,每个函数都接受一个状态输入并产生一个(结果,状态)输出,以一种对你的程序有意义的方式相互插入.一切runState都是为他们提供一个国家起点.

在这种情况下,get它只是一个函数,它将状态作为输入,并返回一个(结果,状态)输出,使得结果是输入状态,状态不变(输出状态是输入状态).换一种说法,get s = (s, s)