让我们看看你的类型:
bind :: (a → StdGen → (b,StdGen)) → (StdGen → (a,StdGen)) → (b,StdGen)
现在,我 100% 同意你的第一点:
Bind 接受一个函数f :: a -> StdGen -> (b,StdGen)和“输出” StdGen -> (a,StdGen)。
但是你的第二个让我担心:
它适用f于aand StdGen。
你从哪里得到类型的值a?你从哪里得到类型的值StdGen?
The answer to both of these questions is "you don't have one lying about"; however, since you do have a StdGen -> (a,StdGen) lying about, you could get both if only you had one more StdGen parameter. And that's where the extra parameter comes from.
Now, a slightly higher-level explanation. Part of the problem (I think) is that these type signatures are a bit too cluttered to read comfortably. We need some abstractions. What we're trying to model here are probability distributions, which we're modeling as their sampling functions. So, we can say a distribution over a is a function that knows how to sample from the distribution and return an a:
type Dist a = StdGen -> (a, StdGen)
Now, not all distributions are so flat as all that. For example, the Bernoulli distribution is "sort of" a Dist Bool, but it's also parameterized on the probability of choosing False. We can write its type thus:
bernoulli :: Double -> Dist Bool
So, we can model parameterized distributions as functions that return distributions; equivalently, we can think of functions that return distributions as parameterized distributions.
Now with this high-level interpretation in mind, the type of bind becomes much more readable:
bind :: (a -> Dist b) -> (Dist a -> Dist b)
This says that bind is the function that tells how to first sample from an a distribution, then use that a as a parameter when sampling from the b distribution. Not only that, but with this type alias, it almost becomes unthinkable to write a type for bind that doesn't have the "extra" argument.