如何“得到”? 实际上/获取/ Haskell 中的初始状态?
我有一个函数:
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我本来打算将其作为评论发布,但决定多解释一下。
严格来说,
get
并不“接受”参数。 我认为正在发生的很多事情都被你看不到的东西所掩盖——状态单子的实例定义。get
实际上是MonadState类的一个方法。 State monad 是 MonadState 的一个实例,提供以下get
定义:换句话说,
get
只是返回一个非常基本的 State monad(记住,monad 可以被认为是作为计算的“包装器”),其中计算中的任何输入s
都将返回一对s
作为结果。接下来我们需要看的是
>>=
,State 是这样定义的:因此,
>>=
将产生一个新的计算,其中在获得初始状态之前不会进行计算(对于处于“包装”形式的所有状态计算都是如此)。 这个新计算的结果是通过将>>=
右侧的任何内容应用于运行左侧计算的结果来实现的。 (这是一个相当令人困惑的句子,可能需要额外阅读一两遍。)我发现“脱糖”所有正在发生的事情非常有用。 这样做需要更多的输入,但应该使您的问题的答案(
get
从哪里获得)非常清晰。 请注意,以下内容应被视为伪代码...这应该清楚地表明我们函数的最终结果是一个新的状态计算,它将需要一个初始值(
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 ofget
: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 inputs
into the computation will return a pair ofs
as the result.The next thing we need to look at is
>>=
, which State defines thusly: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...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 supplieds
as"testtest"
with yourrunState
call. If you substitute "testtest" fors
in the above pseudocode, you'll see that the first thing that happens is we runget
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!它可能会帮助您更深入地了解 State 类型构造函数的真正含义以及 runState 如何使用它。 在 GHCi 中:
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: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 ofState
-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. AllrunState
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)
浏览 Graham Hutton 的用 Haskell 编程<的第 8 章(“函数解析器”) /a> 几次,直到我正确理解它,然后查看教程 All About Monads,为我做了这个点击。
monad 的问题在于,它们对于我们这些来自普通编程背景的人来说非常有用的一些事情非常有用。 需要一些时间才能认识到控制流和处理状态不仅足够相似以至于可以通过相同的机制处理,而且当您退一步足够远时,它们是相同的事情。
当我考虑 C 中的控制结构(
for
和while
等)时,我顿悟了,我意识到迄今为止最常见的控制结构只是简单地放置一个语句在另一个之前。 我花了一年的时间研究 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
andwhile
, 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.