我有一个功能:

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

我几乎可以理解整个函数中发生的事情,并且我开始了解monad。我不明白的是,当我这样做时:

runState (test "testy") "testtest"

'test'中的'get'函数以某种方式得到初始状态<!> quot; testtest <!> quot;。有人可以打破这个并向我解释一下吗?

我感谢任何回复!

有帮助吗?

解决方案

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

严格地说,get不<!>;取<!>一个论点。我想很多正在发生的事情都被你没看到的东西掩盖了 - 状态monad的实例定义。

s实际上是MonadState类的一种方法。 State monad是MonadState的一个实例,提供>>=的以下定义:

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

换句话说,"testtest"只返回一个非常基本的状态monad(记住monad可以被认为是<!> quot; wrapper <!>;用于计算),其中任何输入runState进入计算将返回一对("testtest", "testtest")作为结果。

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

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

所以,<=>将产生一个新的计算,直到它获得一个初始状态才会被计算(当它们在<!>中时,所有状态计算都是如此;包裹<! >“形式”。这个新计算的结果是通过将<=>右侧的任何内容应用于运行左侧计算的结果来实现的。 (这是一个相当混乱的句子,可能需要额外的阅读或两个。)

我发现它对<!>“desugar <!>”非常有用一切都在发生。这样做需要更多的打字,但应该非常清楚地回答你的问题(<=>来自哪里)。请注意,以下内容应视为psuedocode ...

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

这应该很明显,我们函数的最终结果是一个新的状态计算,需要一个初始值(<=>)才能使其余的事情发生。您通过<=>电话提供<=> as <=>。如果你替换<!>“testtest <!>”;对于<=>在上面的伪代码中,您会看到发生的第一件事是我们使用<!>来运行<=>; testtest <!>作为“初始状态”。这会产生<=>等等。

这就是<=>获得初始状态<!>“testtest <!>”的地方。希望这有帮助!

其他提示

它可能会帮助您深入了解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)

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

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

你的get函数是get s = (s, s) - 类型函数的一个重要组成部分,每个函数都接受一个状态输入并产生一个(结果,状态)输出,以对你的程序有意义的方式相互插入。所有<=>确实为他们提供了一个州的起点。

在这种情况下,<=>只是一个将状态作为输入的函数,并返回一个(结果,状态)输出,使得结果是输入状态,状态不变(输出状态是输入状态)。换句话说,<=>

通过Graham Hutton的 quot; Functional Parsers <!>;;) rel =“nofollow noreferrer”>在Haskell编程几次,直到我理解它为止,然后去教程关于Monads ,点击此处。

monad的问题在于它们对于我们这些来自通常编程背景的人发现的几件事非常有用。需要一些时间才能意识到控制流和处理状态不仅足够相似,而且可以通过相同的机制来处理,但是当你退回到足够远的时候,同样的事情。

当我在C(forwhile等)中考虑控制结构时,顿悟就来了,我意识到到目前为止最常见的控制结构只是将一个语句放在另一个语句之前。在我意识到它甚至是一个控制结构之前花了一年时间研究Haskell。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top