代码之家  ›  专栏  ›  技术社区  ›  Rayne

Haskell中的'get'实际上是如何获取初始状态的?

  •  13
  • Rayne  · 技术社区  · 16 年前

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

    runState (test "testy") "testtest"
    

    'test'中的'get'函数以某种方式获取初始状态“testtest”。有人能把它分解并解释给我听吗?

    3 回复  |  直到 16 年前
        1
  •  19
  •   J Cooper    16 年前

    严格来说, get 不“接受”争论。我认为很多正在发生的事情都被你没有看到的东西所掩盖——状态单子的实例定义。

    得到 实际上是MonadState类的一个方法。State monad是MonadState的一个实例,提供了以下定义 得到 :

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

    换言之, 得到 只返回一个非常基本的状态monad(记住,monad可以被视为计算的“包装器”),其中任何输入 s 进入计算将返回一对 s 结果。

    接下来我们需要看的是 >>=

    m >>= k  = State $ \s -> let
        (a, s') = runState m s
        in runState (k a) s'
    

    所以, >>= 将产生一个新的计算,在获得初始状态之前不会进行计算(当所有状态计算处于“打包”形式时,都是如此)。这个新计算的结果是通过应用右侧的任何内容来实现的 >>=

    得到

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

    这应该表明,我们函数的最终结果是一个新的状态计算,需要一个初始值( s s 作为 "testtest" 与你的 runState 电话。如果用“testtest”代替 s 得到 以“testtest”作为“初始状态”。这就产生了 ("testtest", "testtest") 等等。

    所以,这就是 得到

        2
  •  6
  •   JB.    16 年前

    这可能会帮助你更深入地了解 State

    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)
    

    状态 接受两个参数:状态的类型和返回的类型。它被实现为一个函数,接受初始状态并产生返回值和新状态。

    runState 接受这样一个函数,即初始输入,并且(很可能)只将一个函数应用于另一个函数来检索(结果、状态)对。

    test 功能是一个很大的组成部分 状态 -类型函数,每个函数都接受状态输入并产生(结果、状态)输出,以对程序有意义的方式相互插入。全部

    get get s = (s, s)

        3
  •  1
  •   cjs    16 年前

    阅读Graham Hutton的第8章(“函数解析器”) Programming in Haskell All About Monads ,为我点击了一下。

    monad的问题在于,它们在几个方面非常有用,而我们这些来自普通编程背景的人会发现它们非常不同。需要一些时间才能意识到,控制流和处理状态不仅足够相似,可以由相同的机制处理,而且当你退后一步时,它们也是一样的。

    当我考虑C中的控制结构时,我顿悟了( for while