如何“得到”? 实际上/获取/ Haskell 中的初始状态?

发布于 2024-07-25 03:33:28 字数 460 浏览 5 评论 0原文

我有一个函数:

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”函数如何以某种方式获取初始状态“testtest”。 有人可以分解这个并向我解释吗?

我很感激任何回应!

I have a function:

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

I can pretty much understand what goes on throughout this function, and I'm starting to get the hang of monads. What I don't understand is how, when I run this:

runState (test "testy") "testtest"

the 'get' function in 'test' somehow gets the initial state "testtest". Can someone break this down and explain it to me?

I appreciate any responses!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

三生池水覆流年 2024-08-01 03:33:28

我本来打算将其作为评论发布,但决定多解释一下。

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

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

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

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

接下来我们需要看的是 >>=,State 是这样定义的:

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

因此,>>= 将产生一个新的计算,其中在获得初始状态之前不会进行计算(对于处于“包装”形式的所有状态计算都是如此)。 这个新计算的结果是通过将 >>= 右侧的任何内容应用于运行左侧计算的结果来实现的。 (这是一个相当令人困惑的句子,可能需要额外阅读一两遍。)

我发现“脱糖”所有正在发生的事情非常有用。 这样做需要更多的输入,但应该使您的问题的答案(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...

这应该清楚地表明我们函数的最终结果是一个新的状态计算,它将需要一个初始值(s)来使其余部分事情发生了。 您通过 runState 调用将 s 作为 "testtest" 提供。 如果您将上面的伪代码中的 s 替换为“testtest”,您会看到发生的第一件事是我们以“testtest”作为“初始状态”运行 get '。 这会产生 ("testtest", "testtest") 等等。

这就是 get 获取初始状态“testtest”的地方。 希望这可以帮助!

I was originally going to post this as a comment, but decided to expound a bit more.

Strictly speaking, get doesn't "take" an argument. I think a lot of what is going on is masked by what you aren't seeing--the instance definitions of the State monad.

get is actually a method of the MonadState class. The State monad is an instance of MonadState, providing the following definition of get:

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

In other words, get just returns a very basic State monad (remembering that a monad can be thought of as a "wrapper" for a computation), where any input s into the computation will return a pair of s as the result.

The next thing we need to look at is >>=, which State defines thusly:

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

So, >>= is going to yield a new computation, which won't be computed until it gets an initial state (this is true of all State computations when they're in their "wrapped" form). The result of this new computation is achieved by applying whatever is on the right side of the >>= to the result of running the computation that was on the left side. (That's a pretty confusing sentence that may require an additional reading or two.)

I've found it quite useful to "desugar" everything that's going on. Doing so takes a lot more typing, but should make the answer to your question (where get is getting from) very clear. Note that the following should be considered 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...

That should make it obvious that the end result of our function is a new State computation that will need an initial value (s) to make the rest of the stuff happen. You supplied s as "testtest" with your runState call. If you substitute "testtest" for s in the above pseudocode, you'll see that the first thing that happens is we run get with "testtest" as the 'initial state'. This yields ("testtest", "testtest") and so on.

So that's where get gets your initial state "testtest". Hope this helps!

涙—继续流 2024-08-01 03:33:28

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

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

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

您的 test 函数是 State 类型函数的一个大组合,每个函数都接受一个状态输入并产生一个(结果,状态)输出,并以如下方式相互插入:对你的程序有意义。 runState 所做的只是为它们提供一个状态起点。

在这种情况下,get 只是一个以状态作为输入并返回 (result,state) 输出的函数,这样结果就是输入状态,并且状态不变(输出状态是输入状态)。 换句话说,get s = (s, s)

It might help you to take a deeper look at what the State type constructor really is, and how runState uses it. In 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)

State takes two arguments: the type of the state, and the returned type. It is implemented as a function taking the initial state and yielding a return value and the new state.

runState takes such a function, the initial input, and (most probably) just applies one to the other to retrieve the (result,state) pair.

Your test function is a big composition of State-type functions, each taking a state input and yielding a (result,state) output, plugged in one another in a way that makes sense to your program. All runState does is provide them with a state starting point.

In this context, get is simply a function that takes state as an input, and returns a (result,state) output such that the result is the input state, and the state is unchanged (the output state is the input state). In other words, get s = (s, s)

月下伊人醉 2024-08-01 03:33:28

浏览 Graham Hutton 的用 Haskell 编程<的第 8 章(“函数解析器”) /a> 几次,直到我正确理解它,然后查看教程 All About Monads,为我做了这个点击。

monad 的问题在于,它们对于我们这些来自普通编程背景的人来说非常有用的一些事情非常有用。 需要一些时间才能认识到控制流和处理状态不仅足够相似以至于可以通过相同的机制处理,而且当您退一步足够远时,它们是相同的事情。

当我考虑 C 中的控制结构(forwhile 等)时,我顿悟了,我意识到迄今为止最常见的控制结构只是简单地放置一个语句在另一个之前。 我花了一年的时间研究 Haskell,才意识到这甚至是一个控制结构。

Going through chapter 8 ("Functional Parsers") of Graham Hutton's Programming in Haskell several times until I'd properly understood it, followed by a go at the tutorial All About Monads, made this click for me.

The issue with monads is that they are very useful for several things that those of us coming from the usual programming background find quite dissimilar. It takes some time to appreciate that control flow and handling state are not only similar enough that they can be handled by the same mechanism, but are when you step back far enough, the same thing.

An epiphany came when I was considering control structures in C (for and while, etc.), and I realized that by far the most common control structure was simply putting one statement before the other one. It took a year of studying Haskell before I realized that that even was a control structure.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文